Coder Social home page Coder Social logo

canelmas / let Goto Github PK

View Code? Open in Web Editor NEW
530.0 12.0 40.0 2.74 MB

Annotation based simple API flavored with AOP to handle new Android runtime permission model

License: Apache License 2.0

Java 87.00% Groovy 12.28% IDL 0.71%
android library runtime-permissions aop aop-aspectj gradle-plugin kotlin kotlin-android gradle

let's Introduction

Let

Android Arsenal Join the chat at https://gitter.im/canelmas/let

Annotation based simple API flavoured with AOP to handle new Android runtime permission model.

If you check Google's Samples about the new permission model, you'll see a lot of boiler plate code for requesting, handling and retrying the request for required permissions.

Let will minimize the boiler plate code you have to write for requesting and handling permissions and hence help you keep your code more readable.

Let let Handle

Annotate your methods requiring permissions with @AskPermission and let Let handle the rest.

@AskPermission(ACCESS_FINE_LOCATION)
private void getUserLocationAndDoSomething() {
    Toast.makeText(
        SampleActivity.this, 
        "Now that I have the permission I need, I'll get your location and do something with it", 
        Toast.LENGTH_SHORT
    ).show();
    ...
}
@AskPermission({
            Manifest.permission.READ_CONTACTS,
            Manifest.permission.CALL_PHONE,
            Manifest.permission.CAMERA
})
private void skipTutorial() {
    // permissions needed for the best app experience are granted; let's go to the app's home screen
    startActivity(new Intent(this, HomeActivity.class));
}

Let will check these annotated methods and execute them unless the permissions required are granted; otherwise Let will put on hold the method execution and request these permissions at runtime. After examining the permission request result, Let will execute the method already put on hold only if the permissions are granted by user.

Let will also inform about the rationales before making any permission request and tell about denied permissions; whether they're simply denied or with 'Never Ask Again' checked.

Just make sure to override the onRequestPermissionsResult in your Activity or Fragment, where your @AskPermission annotated methods are located:

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    Let.handle(this, requestCode, permissions, grantResults);
}

And make sure your Activity or Fragment implements RuntimePermissionListener in order to get notified about denied permissions and rationales:

public class SampleActivity extends AppCompatActivity implements RuntimePermissionListener {
    
    // ....
    
    @Override
    public void onShowPermissionRationale(List<String> permissions, final RuntimePermissionRequest request) {
        /**
        * you may show permission rationales in a dialog, wait for user confirmation and retry the permission 
        * request by calling request.retry()    
        */               
    }
  
    @Override
    public void onPermissionDenied(List<DeniedPermission> deniedPermissionList) {
        /**
        * Do whatever you need to do about denied permissions:
        *   - update UI
        *   - if permission is denied with 'Never Ask Again', prompt a dialog to tell user
        *   to go to the app settings screen in order to grant again the permission denied 
        */              
    }
    
    //  ...
}

Usage

Add it to your project today!

buildscript {
    repositories {                    
        jcenter()        
    }

    dependencies {        
        classpath 'com.canelmas.let:let-plugin:0.1.11'
    }
}

apply plugin: 'com.android.application'
apply plugin: 'let'

repositories {        
    jcenter()
}

For kotlin :

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath 'com.canelmas.let:let-plugin:1.0.0-beta1'
    }
}

apply plugin: 'com.android.application'
apply plugin: 'let'

repositories {
    jcenter()
}

Proguard

Make sure your proguard rule set includes following lines:

-keep class com.canelmas.let.** { *; }
-keepnames class * implements com.canelmas.let.RuntimePermissionListener

-keepclassmembers class * implements com.canelmas.let.RuntimePermissionListener {
    public void onRequestPermissionsResult(***);
}

-keepclasseswithmembernames class * {
    @com.canelmas.let.* <methods>;
}

License

Copyright 2016 Can Elmas

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

let's People

Contributors

canelmas avatar gitter-badger avatar renaudcerrato avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

let's Issues

permission dialog will not trigger in release apk but works fine in debug

I have come across a new issue today with this brilliant library
The library works perfectly in debug mode, but it will not work in release
the problem is that the function that is annotated by "@AskPermission" will not trigger the permission dialog at all
I have all the mentioned pro guard rules but the problem still exists
what do you think is the problem?

tested on Android 7.0 galaxy s8 and galaxy a7 2017

Let will only execute the annotated method the second time it's called

I'm having this problem with that the annotated method is only executed the second time it's called.
What I mean is that upon the first call to the annotated method the permission dialog is shown correctly but after tapping on Allow the actual method is not executed. I have to rerun the activity for it to actually run.

Method call is not forwarded after granting permission

Running 6.0.1 on a Nexus 6, I noticed that my methods were not called right after granting permissions. After a few debug, I can clearly see that the request code given to onRequestPermissionsResult() has an offset of 256 compared to the task number in DelayedTasks - resulting in a "No delayed task to execute.

It looks like requestPermissions() is adding 256 to the given request code (or ORing it with 0x100 since only first 8 bits can be used as request code).

As a quick and dirty fix, I had to write the following to make it works:

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        Let.handle(this, requestCode & 0xff, permissions, grantResults);
    }

Request a permission causes a crash in Android O

According to some crash reports I'm receiving, there is an issue happening in Android O when a method annotated with @AskPermission is called.

This is the crash stacktrace:

Fatal Exception: com.canelmas.let.LetException: Proceeding with the annotated method failed!
       at com.canelmas.let.RuntimePermissionRequest.proceed(RuntimePermissionRequest.java:139)
       at com.canelmas.let.RuntimePermissionRequest.proceed(RuntimePermissionRequest.java:52)
       at com.canelmas.let.LetAspect.ajc$inlineAccessMethod$com_canelmas_let_LetAspect$com_canelmas_let_RuntimePermissionRequest$proceed(LetAspect.java:1)
       at com.canelmas.let.LetAspect.annotatedMethods(LetAspect.java:57)

EDIT: This happens only if the permissions is granted. Looks like the crash happens when the library tries to invoke the method.

Use Transform API

Consider using Transform API to have a more robust structure and to support kotlin as well.

Right now, weaving is hooked to javaCompile task which is not triggered for kotlin.

Leaked Activity instance

Hi,

Thanks for great library which really makes it easier working with runtime permissions.

However I have discovered really big leak using that library. It might be similar to already reported issue #12.

The problem is directly connected to killing activity and recreating state by Android OS. (For making that easy reproducible enable "Do not keep activities" in Developer settings.)

Really simple code for reproducing mentioned issue:

public class MainActivity extends AppCompatActivity implements RuntimePermissionListener {

    private static final String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "Created " + this.hashCode());
        final Button cameraButton = (Button) findViewById(R.id.camera);
        cameraButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.i(TAG, "Access prompted for " + MainActivity.this.hashCode());
                someMethodWhichUsesCamera();
            }
        });
    }

    @AskPermission({Manifest.permission.CAMERA})
    private void someMethodWhichUsesCamera() {
        Log.i(TAG, "Camera accessible for " + this.hashCode());
    }

    @Override
    public void onShowPermissionRationale(List<String> permissionList, RuntimePermissionRequest permissionRequest) {
        //do nothing
    }

    @Override
    public void onPermissionDenied(List<DeniedPermission> deniedPermissionList) {
        //do nothing
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        Let.handle(this, requestCode, permissions, grantResults);
    }
}

As you can this code does nothing, but important thing is the hashCode value printed in logs.

For normal flow result is following:

sample.android.let.activityleak I/MainActivity: Created 48167139
sample.android.let.activityleak I/MainActivity: Access prompted for 48167139
sample.android.let.activityleak I/MainActivity: Camera accessible for 48167139

By normal flow I mean: user clicks button which asks for permission and permission is granted immediately.

That flow is in 99% correct, but imagine following scenario: (with "Do not keep activities")

  1. User clicks button
  2. User is asked for permission
  3. User puts app to background when system dialog is displayed
    4 User restores application
  4. User clicks "Allow"

The output for such scheme is:

sample.android.let.activityleak I/MainActivity: Created 190272224
sample.android.let.activityleak I/MainActivity: Access prompted for 190272224
sample.android.let.activityleak I/MainActivity: Created 125354589
sample.android.let.activityleak I/MainActivity: Camera accessible for 190272224

Let is calling someMethodWhichUsesCamera on killed Activity instance, thus besides this leak other exception may arrive like NPE.

Thanks

Let crash on M devices (and N devices)

I get the same issue getAnnotation(java.lang.class) on a null object reference as posted in this issue

https://code.google.com/p/android/issues/detail?id=203109&q=permission&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&num=500
Code is here:

@AskPermission({Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION})
public void onEvent(NewTastingEvent event) {
    // Si pas d'internet
    if (MilleZimU.getInstance().isOnline()) {

        // Si app trop vielle
        if (AppManager.getInstance().isAbleToWork()) {

            // Si connecté
            if (MilleZimU.getInstance().getUserInstance() != null) {
                // Si degust pas finie


                DateTime thirtyMinAgo = DateTime.now().minusMinutes(30);
                if (getUser().hasIncompletedVoucher(thirtyMinAgo) && getUser().getOptions().getRetrieve().getStatus() == UserOption.ENABLE) {
                    TastingVoucher incompleteVoucher = getUser().getUncompletedVoucher(thirtyMinAgo);
                    new UncompletedTastingDialog(this, incompleteVoucher.id).show();
                }
                // Si encore des coupon
                else {
                    if (MilleZimU.getInstance().getUserInstance().hasValidVoucher() > 0 || getUser().getOptions().getFree().getStatus() == UserOption.ENABLE) {
                        // Si Permission
                        // Attention ordre important
                        startPhotoActivity();
                        EventBus.getDefault().post(new PrepareVoucherEvent(MilleZimU.getInstance().getUserInstance().getClosestValidVoucher()));
                    }
                    // Si Pas de coupon
                    else
                        new UnpaidedTastingStartDialog(this).show();
                }
            }
            // Si pas connecté
            else {
                new UnloggedTastingStartDialog(this).show();
                // Si essai

                // Si enregistrement
            }
        } else {
            AppManager.getInstance().impactVersionChange(this);
        }
    } else {
        new InternetLessDialog(this).show();
    }


}

public void startPhotoActivity() {
    Intent i = new Intent(this, NavigationActivity.class);
    startActivity(i);
    finish();
}


@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    Let.handle(this, requestCode, permissions, grantResults);
}

@Override
public void onShowPermissionRationale(List<String> permissionList, RuntimePermissionRequest permissionRequest) {
    new PermissionGrantingDialog(HomeActivity.this, "Gestion des permissions", "MilleZimU a besoin de la fonction STOCKAGE (sauvegarde du compte), APPAREIL PHOTO (enregistrement de l'étiquette) et POSITION (lieu de dégustation) pour pouvoir continuer. Veuillez accepter les demandes qui suivent", permissionRequest).show();
}

@Override
public void onPermissionDenied(List<DeniedPermission> deniedPermissionList) {
}

This is working fine on:

  • Android L devices
  • Android M emulator

This failed on Nexus 5 on Android M

Button set text not working when method has @AskPermission annotation

Hi, it seems there is a problem while I'm trying to update the text of the button in a method like this :


   @AskPermission({
            Manifest.permission.SEND_SMS,
            Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.INTERNET
    })
    private void ChangeServiceRunning() {

       btn.setText("Stop Service!");
       btn.setBackgroundResource(R.drawable.round_active_button);

    }

Use with Kotlin

I am currently using this library in an activity written in kotlin. I think it is not taking annotations

@AskPermission(Manifest.permission.READ_SMS) private fun checkSMSPermission() { permissionListener?.permissionGranted() // this method is called }

It is calling listener but not checking for permissions. Is this library not compatible with kotlin?

java.lang.VerifyError: ActivityWelcome$AjcClosure1

Ever since adding the AskPermissions annotations I've been getting the VerifyError below:

java.lang.VerifyError: ActivityWelcome$AjcClosure1

This is honestly my first time seeing an error of this sort so I'll keep digging to see if there's a way to resolve on my own. Posting here just incase others experience a similar issue or have suggestions for resolving.

  @AskPermission(Manifest.permission.ACCESS_FINE_LOCATION)
  private void startTrackingLocation() {
    mTracker = LocationTracker.getInstance(this);
    mTracker.startTracking();
  }

EDIT

Forgot to mention this is happening on android 4.4.1 and 4.4.2 from what I can tell so far.

Let annotation crashes on Android N devices

Hey there,
Thought you'd like to know about this crash on Android N:

java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String[] com.canelmas.let.AskPermission.value()' on a null object reference
    at com.canelmas.let.RuntimePermissionRequest.proceed(RuntimePermissionRequest.java:61)
    at com.canelmas.let.RuntimePermissionRequest.proceed(RuntimePermissionRequest.java:52)
    at com.canelmas.let.LetAspect.ajc$inlineAccessMethod$com_canelmas_let_LetAspect$com_canelmas_let_RuntimePermissionRequest$proceed(LetAspect.java:1)
    at com.canelmas.let.LetAspect.annotatedMethods(LetAspect.java:57)

Here's the line of code where it crashed:
@AskPermission({ Manifest.permission.ACCESS_FINE_LOCATION })

Just thought I'd give you a heads up for when the full OS release actually comes out. Love the library!

Logger flooding

Hey, I like using your library, it's super convenient, thank you for your work!

But can you please remove the logger or add the possibility to turn it off? It's really annoying.

Best Regards!

Loss data after rotation.

After click on "show first contact" button, if I rotate the device, the activity is recreated losing the data shown.

Problems using with Android Library

Using Let with an android library, there is this error:

Transforms with scopes '[EXTERNAL_LIBRARIES]' cannot be applied to library projects.

Delayed execution failed error when asking for multiple permissions

For your reference.

FATAL EXCEPTION: main

Process: com.mobility.iz.tstar, PID: 13347

java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=0, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.mobility.iz.tstar/com.mobility.ui.DashboardActivity}: com.canelmas.let.LetException: Delayed Execution Failed!

    at android.app.ActivityThread.deliverResults(ActivityThread.java:3699)

    at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742)

    at android.app.ActivityThread.-wrap16(ActivityThread.java)

    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393)

    at android.os.Handler.dispatchMessage(Handler.java:102)

    at android.os.Looper.loop(Looper.java:148)

    at android.app.ActivityThread.main(ActivityThread.java:5417)

    at java.lang.reflect.Method.invoke(Native Method)

    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)

    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

 Caused by: com.canelmas.let.LetException: Delayed Execution Failed!

    at com.canelmas.let.Let.handle(Let.java:74)

    at com.mobility.ui.DashboardActivity.onRequestPermissionsResult(DashboardActivity.java:71)

    at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6582)

    at android.app.Activity.dispatchActivityResult(Activity.java:6460)

    at android.app.ActivityThread.deliverResults(ActivityThread.java:3695)

    at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742) 

    at android.app.ActivityThread.-wrap16(ActivityThread.java) 

    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393) 

    at android.os.Handler.dispatchMessage(Handler.java:102) 

    at android.os.Looper.loop(Looper.java:148) 

    at android.app.ActivityThread.main(ActivityThread.java:5417) 

    at java.lang.reflect.Method.invoke(Native Method) 

    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 

    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

 Caused by: com.canelmas.let.LetException: Future Task execution failed!

    at com.canelmas.let.DelayedTasks$Task.call(DelayedTasks.java:68)

    at com.canelmas.let.DelayedTasks$Task.execute(DelayedTasks.java:59)

    at com.canelmas.let.Let.handle(Let.java:72)

    at com.mobility.ui.DashboardActivity.onRequestPermissionsResult(DashboardActivity.java:71) 

    at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6582) 

    at android.app.Activity.dispatchActivityResult(Activity.java:6460) 

    at android.app.ActivityThread.deliverResults(ActivityThread.java:3695) 

    at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742) 

    at android.app.ActivityThread.-wrap16(ActivityThread.java) 

    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393) 

    at android.os.Handler.dispatchMessage(Handler.java:102) 

    at android.os.Looper.loop(Looper.java:148) 

    at android.app.ActivityThread.main(ActivityThread.java:5417) 

    at java.lang.reflect.Method.invoke(Native Method) 

    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 

    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

 Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

    at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1489)

    at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1507)

    at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:634)

    at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:613)

    at com.mobility.ui.DashboardActivity.init_aroundBody0(DashboardActivity.java:65)

    at com.mobility.ui.DashboardActivity$AjcClosure1.run(DashboardActivity.java:1)

    at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:149)

    at com.canelmas.let.DelayedTasks$Task.call(DelayedTasks.java:66)

    at com.canelmas.let.DelayedTasks$Task.execute(DelayedTasks.java:59) 

    at com.canelmas.let.Let.handle(Let.java:72) 

    at com.mobility.ui.DashboardActivity.onRequestPermissionsResult(DashboardActivity.java:71) 

    at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6582) 

    at android.app.Activity.dispatchActivityResult(Activity.java:6460) 

    at android.app.ActivityThread.deliverResults(ActivityThread.java:3695) 

    at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742) 

    at android.app.ActivityThread.-wrap16(ActivityThread.java) 

    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393) 

    at android.os.Handler.dispatchMessage(Handler.java:102) 

    at android.os.Looper.loop(Looper.java:148) 

    at android.app.ActivityThread.main(ActivityThread.java:5417) 

    at java.lang.reflect.Method.invoke(Native Method) 

    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 

    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

P.S. Thanks a ton for the library! 👍

onPermissionDenied() never called

I have @AskPermission in my fragment that implemented RuntimePermissionListener, something like this:

@AskPermission({CAMERA, WRITE_EXTERNAL_STORAGE}) private void startCamera() {
        //Display camera view
}

It works when the permissions got granted, but when I tried to handle denied situation, onPermissionDenied() never gets called . Just wonder when it calls onPermissionDenied()?

Asking for permission before starting a download session with download manager brings "Screen overlay detected" screen on Samsung Devices (Tested with s6 and s7)

When I try to ask for "WRITE_EXTERNAL_STORAGE" before I initiate a download session using the built-in download manager, the "screen overlay detected" message shows up. Look at the code below:

@AskPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
    private void downloadFile() {
        String downloadDir = "/photo";
        File direct = new File(Environment.getExternalStorageDirectory()
                + downloadDir);
        if (!direct.exists())
            direct.mkdirs();

        String fileExtension = ".jpg";
        String filename = name;

        DownloadManager downloadManager = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        request.setTitle("title");
        request.setDescription("downloading...");
        request.setDestinationInExternalPublicDir(downloadDir,
                filename + fileExtension);
        request.allowScanningByMediaScanner();
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        downloadManager.enqueue(request);
        Toast toast = Toast.makeText(getActivity(), "download started", Toast.LENGTH_LONG);
        LinearLayout toastLayout = (LinearLayout) toast.getView();
        TextView toastTV = (TextView) toastLayout.getChildAt(0);
        toastTV.setTypeface(Typeface.createFromAsset(getActivity().getAssets(), "RoyaBold.ttf"));
        toast.show();
    }

If you play with the screen and deny the permission one time, and dismiss the "screen overlay detected" dialog, I can then grant the permission. Strangely if I go to settings, disable the permission, and run this method again, it will bring the permission dialog successfully this time (without showing the screen overlay detected dialog)

What is the problem?

Memory leak detected by LeakCanary

Hi,

When using this library, com.canelmas.let.DelayedTasks.tasks appears to leak an instance of the fragment that uses it. Below is a LeakCanary log. Please let me know if I can provide any additional information to help debug this issue.

Thanks!

In com.sample.android.debug:0.0.1:1.
* com.sample.android.ui.storelocator.StoreLocatorFragment has leaked:
* GC ROOT static com.canelmas.let.DelayedTasks.tasks
* references java.util.Collections$SynchronizedMap.m
* references java.util.HashMap.table
* references array java.util.HashMap$HashMapEntry[].[2]
* references java.util.HashMap$HashMapEntry.value
* references com.canelmas.let.DelayedTasks$Task.joinPoint
* references org.aspectj.runtime.reflect.JoinPointImpl._this
* leaks com.sample.android.ui.storelocator.StoreLocatorFragment instance

* Retaining: 0.92 KB.
* Reference Key: ecf51f74-d8fa-428e-9fbc-6779906aa8e6
* Device: Huawei google Nexus 6P angler
* Android Version: 6.0.1 API: 23 LeakCanary: 1.4-beta1 02804f3
* Durations: watch=5071ms, gc=181ms, heap dump=6489ms, analysis=58273ms

* Details:
* Class com.canelmas.let.DelayedTasks
|   static $staticOverhead = byte[8]@326231041 (0x1371e401)
|   static tasks = java.util.Collections$SynchronizedMap@326207008 (0x13718620)
* Instance of java.util.Collections$SynchronizedMap
|   static $staticOverhead = byte[8]@1874459337 (0x6fb9fac9)
|   static serialVersionUID = 1978198479659022715
|   m = java.util.HashMap@326184768 (0x13712f40)
|   mutex = java.util.Collections$SynchronizedMap@326207008 (0x13718620)
|   shadow$_klass_ = java.util.Collections$SynchronizedMap
|   shadow$_monitor_ = 0
* Instance of java.util.HashMap
|   static MINIMUM_CAPACITY = 4
|   static serialPersistentFields = java.io.ObjectStreamField[1]@1873718864 (0x6faeae50)
|   static EMPTY_TABLE = java.util.HashMap$HashMapEntry[2]@1873718408 (0x6faeac88)
|   static serialVersionUID = 362498820763181265
|   static $staticOverhead = byte[48]@1874489281 (0x6fba6fc1)
|   static MAXIMUM_CAPACITY = 1073741824
|   static DEFAULT_LOAD_FACTOR = 0.75
|   entryForNullKey = null
|   entrySet = null
|   keySet = null
|   modCount = 4
|   size = 2
|   table = java.util.HashMap$HashMapEntry[4]@326288640 (0x1372c500)
|   threshold = 3
|   values = null
|   keySet = null
|   valuesCollection = null
|   shadow$_klass_ = java.util.HashMap
|   shadow$_monitor_ = 0
* Array of java.util.HashMap$HashMapEntry[]
|   [0] = null
|   [1] = null
|   [2] = java.util.HashMap$HashMapEntry@329076224 (0x139d4e00)
|   [3] = null
* Instance of java.util.HashMap$HashMapEntry
|   hash = 1262722378
|   key = java.lang.Integer@1873706008 (0x6fae7c18)
|   next = java.util.HashMap$HashMapEntry@326288672 (0x1372c520)
|   value = com.canelmas.let.DelayedTasks$Task@329076192 (0x139d4de0)
|   shadow$_klass_ = java.util.HashMap$HashMapEntry
|   shadow$_monitor_ = 0
* Instance of com.canelmas.let.DelayedTasks$Task
|   joinPoint = org.aspectj.runtime.reflect.JoinPointImpl@329074624 (0x139d47c0)
|   permissionList = java.util.ArrayList@329076032 (0x139d4d40)
|   requestCode = 1
|   shadow$_klass_ = com.canelmas.let.DelayedTasks$Task
|   shadow$_monitor_ = 0
* Instance of org.aspectj.runtime.reflect.JoinPointImpl
|   _this = com.sample.android.ui.storelocator.StoreLocatorFragment@327039024 (0x137e3830)
|   arc = com.sample.android.ui.storelocator.StoreLocatorFragment$AjcClosure1@329074688 (0x139d4800)
|   args = java.lang.Object[0]@321742640 (0x132d6730)
|   staticPart = org.aspectj.runtime.reflect.JoinPointImpl$StaticPartImpl@322750176 (0x133cc6e0)
|   target = com.sample.android.ui.storelocator.StoreLocatorFragment@327039024 (0x137e3830)
|   shadow$_klass_ = org.aspectj.runtime.reflect.JoinPointImpl
|   shadow$_monitor_ = 0
* Instance of com.sample.android.ui.storelocator.StoreLocatorFragment
|   static PIN_LABELS = java.lang.String[5]@322750400 (0x133cc7c0)
|   static ajc$tjp_0 = org.aspectj.runtime.reflect.JoinPointImpl$StaticPartImpl@322750176 (0x133cc6e0)
|   static MAX_PINS_ON_MAP = 5
|   static $staticOverhead = byte[32]@320919553 (0x1320d801)
|   static $change = null
|   analytics = com.google.firebase.analytics.FirebaseAnalytics@319747056 (0x130ef3f0)
|   api = $Proxy0@315108288 (0x12c82bc0)
|   googleMap = com.google.android.gms.maps.GoogleMap@328919184 (0x139ae890)
|   locationName = java.lang.String@321788944 (0x132e1c10)
|   mapView = com.google.android.gms.maps.MapView@328363008 (0x13926c00)
|   searchBoxView = com.sample.android.ui.widget.FilterableSearchBoxView@328364032 (0x13927000)
|   subscriptions = rx.subscriptions.CompositeSubscription@326522400 (0x13765620)
|   view = android.support.percent.PercentRelativeLayout@328361984 (0x13926800)
|   unbinder = butterknife.Unbinder$1@321742608 (0x132d6710)
|   mAdded = false
|   mAllowEnterTransitionOverlap = null
|   mAllowReturnTransitionOverlap = null
|   mAnimatingAway = null
|   mArguments = null
|   mBackStackNesting = 0
|   mCalled = true
|   mCheckedForLoaderManager = false
|   mChildFragmentManager = null
|   mContainer = null
|   mContainerId = 0
|   mDeferStart = false
|   mDetached = false
|   mEnterTransition = null
|   mEnterTransitionCallback = null
|   mExitTransition = null
|   mExitTransitionCallback = null
|   mFragmentId = 0
|   mFragmentManager = null
|   mFromLayout = false
|   mHasMenu = false
|   mHidden = false
|   mHost = null
|   mInLayout = false
|   mIndex = -1
|   mInnerView = null
|   mLoaderManager = null
|   mLoadersStarted = false
|   mMenuVisible = true
|   mNextAnim = 0
|   mParentFragment = null
|   mReenterTransition = java.lang.Object@321742496 (0x132d66a0)
|   mRemoving = false
|   mRestored = false
|   mRetainInstance = false
|   mRetaining = false
|   mReturnTransition = java.lang.Object@321742496 (0x132d66a0)
|   mSavedFragmentState = null
|   mSavedViewState = android.util.SparseArray@321537568 (0x132a4620)
|   mSharedElementEnterTransition = null
|   mSharedElementReturnTransition = java.lang.Object@321742496 (0x132d66a0)
|   mState = 0
|   mStateAfterAnimating = 0
|   mTag = null
|   mTarget = null
|   mTargetIndex = -1
|   mTargetRequestCode = 0
|   mUserVisibleHint = true
|   mView = null
|   mWho = null
|   shadow$_klass_ = com.sample.android.ui.storelocator.StoreLocatorFragment
|   shadow$_monitor_ = 0
* Excluded Refs:
| Field: android.view.inputmethod.InputMethodManager.mNextServedView
| Field: android.view.inputmethod.InputMethodManager.mServedView
| Field: android.view.inputmethod.InputMethodManager.mServedInputConnection
| Field: android.view.Choreographer$FrameDisplayEventReceiver.mMessageQueue (always)
| Thread:FinalizerWatchdogDaemon (always)
| Thread:main (always)
| Thread:LeakCanary-Heap-Dump (always)
| Class:java.lang.ref.WeakReference (always)
| Class:java.lang.ref.SoftReference (always)
| Class:java.lang.ref.PhantomReference (always)
| Class:java.lang.ref.Finalizer (always)
| Class:java.lang.ref.FinalizerReference (always)
| Root Class:android.os.Binder (always)

Load time

The first load is slow on my Moto G 2014, take about 10 seconds.
is there any way to speed it up?

Let beta wrong dependency included

I tried updating Let from 0.1.11 to the new beta version 1.0.0-beta1 (also tested 1.0.0-beta2). Gradle build the APK without any errors but for some reason it included the wrong Javax.activation.* files, this is giving me errors for the JavaMail library that I am using.

I have no idea why this is happening, and after downgrading back to 0.1.11 it was fixed. I made a ticket in JavaMail first because I thought there was an issue with JavaMail: jakartaee/mail-api#378

Even though after downgrading it was fixed for me I would like to know if this can be investigated and fixed in future versions.

If you need any info please let me know.

Lower 8 bits for requestCode

Only 8 bits request codes should be used for requestPermissions(Activity activity, String[] permissions, int requestCode)

Otherwise java.lang.IllegalArgumentException: Can only use lower 8 bits for requestCode is thrown.

Fix : #10

com.canelmas.let.LetException: Delayed Execution Failed!

I'm getting following error using let:

`Fatal Exception: java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=0, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {de.fsrfb4.fb4/de.fsrfb4.fb4.TicketActivity}: com.canelmas.let.LetException: Delayed Execution Failed!
   at android.app.ActivityThread.deliverResults(ActivityThread.java:3758)
   at android.app.ActivityThread.handleSendResult(ActivityThread.java:3801)
   at android.app.ActivityThread.access$1400(ActivityThread.java:157)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:148)
   at android.app.ActivityThread.main(ActivityThread.java:5551)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
Caused by com.canelmas.let.LetException: Delayed Execution Failed!
   at com.canelmas.let.Let.handle(Let.java:74)
   at de.fsrfb4.fb4.TicketActivity.onRequestPermissionsResult(TicketActivity.java:161)
   at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6588)
   at android.app.Activity.dispatchActivityResult(Activity.java:6467)
   at android.app.ActivityThread.deliverResults(ActivityThread.java:3754)
   at android.app.ActivityThread.handleSendResult(ActivityThread.java:3801)
   at android.app.ActivityThread.access$1400(ActivityThread.java:157)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:148)
   at android.app.ActivityThread.main(ActivityThread.java:5551)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
Caused by com.canelmas.let.LetException: Future Task execution failed!
   at com.canelmas.let.DelayedTasks$Task.call(DelayedTasks.java:68)
   at com.canelmas.let.DelayedTasks$Task.execute(DelayedTasks.java:59)
   at com.canelmas.let.Let.handle(Let.java:72)
   at de.fsrfb4.fb4.TicketActivity.onRequestPermissionsResult(TicketActivity.java:161)
   at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6588)
   at android.app.Activity.dispatchActivityResult(Activity.java:6467)
   at android.app.ActivityThread.deliverResults(ActivityThread.java:3754)
   at android.app.ActivityThread.handleSendResult(ActivityThread.java:3801)
   at android.app.ActivityThread.access$1400(ActivityThread.java:157)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:148)
   at android.app.ActivityThread.main(ActivityThread.java:5551)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)`

This is the corresponding code:

@AskPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
private void selectFile()
{
    showFileChooserDialog();
}

private void showFileChooserDialog()
{
    new FileChooserDialog.Builder(TicketActivity.this)
            .mimeType("application/pdf")
            .chooseButton(R.string.wählen)
            .cancelButton(R.string.abbrechen)
            .show();
}

What am i doing wrong?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.