nabinbhandari / Android-Permissions

Library for easy handling of android run-time permissions.
410 stars 84 forks source link

Crash on Android 9.0 when using this library outside of an Activity #11

Closed zztmercury closed 5 years ago

zztmercury commented 5 years ago

android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want? at android.app.ContextImpl.startActivity(ContextImpl.java:1072) at android.app.ContextImpl.startActivity(ContextImpl.java:1041)

With Android 9, you cannot start an activity from a non-activity context unless you pass the intent flag FLAG_ACTIVITY_NEW_TASK. If you attempt to start an activity without passing this flag, the activity does not start, and the system prints a message to the log.

nabinbhandari commented 5 years ago

I tried to run the sample project in android 9 emulator and used application context to request permissions, but it worked as expected. Can you provide me a minimal code that leads to the crash?

zztmercury commented 5 years ago
public class MyService extends Service {
    private static final String TAG = "MyService";
    private LocalBinder mBinder = new LocalBinder();
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    public class LocalBinder extends Binder {
        public MyService getService(){
            return MyService.this;
        }
    }

    public void requestWriteExternalStoragePermission() {
        Permissions.check(this, Manifest.permission.WRITE_EXTERNAL_STORAGE, "need permissions", new PermissionHandler() {
            @Override
            public void onGranted() {
                Log.d(TAG, "onGranted");
            }
        });
    }
}
zztmercury commented 5 years ago

Start with Permission WRITE_EXTERNAL_STORAGE not granted

nabinbhandari commented 5 years ago

Hello, sorry for the late response. I used your code and It is still working.

In MainActivity, I added the following code:

    private boolean mServiceBound = false;
    MyService mBoundService;

    private ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mServiceBound = false;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            MyService.LocalBinder myBinder = (MyService.LocalBinder) service;
            mBoundService = myBinder.getService();
            mServiceBound = true;
        }
    };

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, MyService.class);
        startService(intent);
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        if (mServiceBound) {
            unbindService(mServiceConnection);
            mServiceBound = false;
        }
    }

Then I called mBoundService.requestWriteExternalStoragePermission(); on button click, it worked just fine in my emulator. Is there anything that I'm missing? Have you encountered this problem in single device or in emulator too?

polesapart commented 5 years ago

I'm not sure if this fits the OP's project or not, but consider the case where you don't have an Activity, i.e. you're running from a service started e.g. by intercepting the android.intent.action.BOOT_COMPLETED or more recently from an WorkManager task (where you don't have neither an activity nor a service!).

The workaround on the code as is is to instantiate an activity just for calling Permissions.check.

The fix to avoid that would be to provide an option in the Options object (i.e. a boolean for e.g. named newTask) and then:

 else {
                PermissionsActivity.permissionHandler = handler;
                ArrayList<String> permissionsList = new ArrayList<>(permissionsSet);
                Intent intent = new Intent(context, PermissionsActivity.class)
                        .putExtra(PermissionsActivity.EXTRA_PERMISSIONS, permissionsList)
                        .putExtra(PermissionsActivity.EXTRA_RATIONALE, rationale)
                        .putExtra(PermissionsActivity.EXTRA_OPTIONS, options);
               if (options.newTask) {
                      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
               }
                context.startActivity(intent);
            }