Giter Site home page Giter Site logo

rxpermissions's Introduction

RxPermissions

BuildVersion Build Status

This library allows the usage of RxJava with the new Android M permission model.

Setup

To use this library your minSdkVersion must be >= 14.

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

dependencies {
    implementation 'com.github.tbruyelle:rxpermissions:0.12'
}

Usage

Create a RxPermissions instance :

final RxPermissions rxPermissions = new RxPermissions(this); // where this is an Activity or Fragment instance

NOTE: new RxPermissions(this) the this parameter can be a FragmentActivity or a Fragment. If you are using RxPermissions inside of a fragment you should pass the fragment instance(new RxPermissions(this)) as constructor parameter rather than new RxPermissions(fragment.getActivity()) or you could face a java.lang.IllegalStateException: FragmentManager is already executing transactions.

Example : request the CAMERA permission (with Retrolambda for brevity, but not required)

// Must be done during an initialization phase like onCreate
rxPermissions
    .request(Manifest.permission.CAMERA)
    .subscribe(granted -> {
        if (granted) { // Always true pre-M
           // I can control the camera now
        } else {
           // Oups permission denied
        }
    });

If you need to trigger the permission request from a specific event, you need to setup your event as an observable inside an initialization phase.

You can use JakeWharton/RxBinding to turn your view to an observable (not included in the library).

Example :

// Must be done during an initialization phase like onCreate
RxView.clicks(findViewById(R.id.enableCamera))
    .compose(rxPermissions.ensure(Manifest.permission.CAMERA))
    .subscribe(granted -> {
        // R.id.enableCamera has been clicked
    });

If multiple permissions at the same time, the result is combined :

rxPermissions
    .request(Manifest.permission.CAMERA,
             Manifest.permission.READ_PHONE_STATE)
    .subscribe(granted -> {
        if (granted) {
           // All requested permissions are granted
        } else {
           // At least one permission is denied
        }
    });

You can also observe a detailed result with requestEach or ensureEach :

rxPermissions
    .requestEach(Manifest.permission.CAMERA,
             Manifest.permission.READ_PHONE_STATE)
    .subscribe(permission -> { // will emit 2 Permission objects
        if (permission.granted) {
           // `permission.name` is granted !
        } else if (permission.shouldShowRequestPermissionRationale) {
           // Denied permission without ask never again
        } else {
           // Denied permission with ask never again
           // Need to go to the settings
        }
    });

You can also get combined detailed result with requestEachCombined or ensureEachCombined :

rxPermissions
    .requestEachCombined(Manifest.permission.CAMERA,
             Manifest.permission.READ_PHONE_STATE)
    .subscribe(permission -> { // will emit 1 Permission object
        if (permission.granted) {
           // All permissions are granted !
        } else if (permission.shouldShowRequestPermissionRationale)
           // At least one denied permission without ask never again
        } else {
           // At least one denied permission with ask never again
           // Need to go to the settings
        }
    });

Look at the sample app for more.

Important read

As mentioned above, because your app may be restarted during the permission request, the request must be done during an initialization phase. This may be Activity.onCreate, or View.onFinishInflate, but not pausing methods like onResume, because you'll potentially create an infinite request loop, as your requesting activity is paused by the framework during the permission request.

If not, and if your app is restarted during the permission request (because of a configuration change for instance), the user's answer will never be emitted to the subscriber.

You can find more details about that here.

Status

This library is still beta, so contributions are welcome. I'm currently using it in production since months without issue.

Benefits

  • Avoid worrying about the framework version. If the sdk is pre-M, the observer will automatically receive a granted result.

  • Prevents you to split your code between the permission request and the result handling. Currently without this library you have to request the permission in one place and handle the result in Activity.onRequestPermissionsResult().

  • All what RX provides about transformation, filter, chaining...

License

Copyright (C) 2015 Thomas Bruyelle

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.

rxpermissions's People

Contributors

agramian avatar aleksandermielczarek avatar egor-n avatar eleventigers avatar epool avatar friederbluemle avatar galuszkak avatar hoeggi avatar jadyli avatar javiergamarra avatar kushtrimpacaj avatar nhaarman avatar o0starshine0o avatar patloew avatar pavelsynek avatar swolfand avatar takecare avatar tarasantoshchuk avatar tbruyelle avatar tevjef avatar vanniktech avatar wangyongf 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  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

rxpermissions's Issues

requestEach and each permission should show Rationale

This question makes me crazy。。。。

I need request
Manifest.permission.READ_PHONE_STATE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION
Each needs to judge whether need to show rationale.
And each needs to judge isgranted before request.

Do you have a good idea about use RX

Ask permission again

Once the user denies permission, re-asking it doesn't show up the dialog to allow or deny.
I need to restart the application to make it appear again.

Is it by design? Or I'm missing something ?

RxPermissions.getInstance(context)
    .request(Manifest.permission.ACCESS_FINE_LOCATION)
    .subscribe(..)

No possibility for an explanation popup or the like

As stated in Requesting permissions one should check whether you need to explain the necessity to request certain permissions by using [ActivityCompat.shouldShowRequestPermissionRationale](http://developer.android.com/reference/android/support/v4/app/ActivityCompat.html#shouldShowRequestPermissionRationale%28android.app.Activity, java.lang.String%29)

Right now the library offers no possibility to handle this case, should be easy to implement though...

Some questions.

Before I fork and start working on changes, I would like to know your views on following.

  1. On RxPermission's initializer you have used getApplicationContext() any reason of doing so?? IMO just a local context should be enough.
  2. Have you thought on passing Fragments and activities to play nicely with lifecycle? I am planning to extend it with Trello's RxLifeCycle library.
  3. How about a Kotlin sibling of this library?
    One more question
  4. There are some bits of code that should be delegated to support lib rather than doing it manually, any reason not doing that?

Lacks implementation or documentation on how to handle rationale dialog requests

A part of the flow of the permission system on Android M is to request a rationale dialog from the consumer the second and later times of requesting a given permission. How does this library handle that?

If it handles it, would be nice if this was documented in the README and implemented in the sample. If not implemented: Could it be? Or does that flow not fit into this library?

targetsdk pre 23

Does it have to be the target SDK 23?

I want all permissions to be granted and I want to see permission dialog if user has already denied permission

Result is lost with Do not keep activities ON

Hello,

The result of permission request is lost in the following case (can be easily reproduced with your sample):

  1. Go to Settings and enable "Do not keep activities" mode.
  2. Open the sample.
  3. Press "Enable camera"
  4. Press Home button.
  5. Retrieve the app from the recent apps.
  6. Press "Allow".
    Actual result: Noting happens.
    Expected result: Camera is opened.

While staying a rare case, it's a bit annoying, especially when using the library in production. I would be interested to know if you have any idea how to avoid this issue (except that to reject requesting permission by a trigger in a whole).

Thank you in advance.

add android.permission.CAMERA 权限同时检测时一直失败

    RxView.clicks(findViewById(R.id.photo))
            .compose(RxPermissions.getInstance(this).ensure(Manifest.permission.READ_EXTERNAL_STORAGE))
            .subscribe(new Action1<Boolean>() {
                @Override
                public void call(Boolean granted) {
                    if (granted) {
                        PhotoPickerIntent intent = new PhotoPickerIntent(DiaryPost.this);
                        intent.setPhotoCount(1);
                        intent.setShowCamera(true);
                        intent.setShowGif(false);
                        startActivityForResult(intent, REQUEST_CODE);
                    } else {
                        showToast(R.string.no_permission);
                    }
                }
            });

Re-requesting permission fails

In my app, I’m trying to re-request the permission every time it fails via a non-cancelable AlertDialog, where the only action requests the permission again. However, when re-requesting the permission, onCompleted() happens, without onNext():

// First request:
D/MainFragment: [@Observable :: @InClass -> MainFragment :: @Method -> getPermissionsObservable()]
D/MainFragment: [@Observable#getPermissionsObservable -> onSubscribe()]
D/MainFragment: [@Observable#getPermissionsObservable -> onNext() -> false]
D/MainFragment: [@Observable#getPermissionsObservable -> @SubscribeOn -> main :: @ObserveOn -> main]
D/MainFragment: [@Observable#getPermissionsObservable -> onUnsubscribe()]
// Second (retry) request:
D/MainFragment: [@Observable :: @InClass -> MainFragment :: @Method -> getPermissionsObservable()]
D/MainFragment: [@Observable#getPermissionsObservable -> onSubscribe()]
D/MainFragment: [@Observable#getPermissionsObservable -> onCompleted()]
D/MainFragment: [@Observable#getPermissionsObservable -> onTerminate()]
D/MainFragment: [@Observable#getPermissionsObservable -> @Emitted -> 0 elements :: @Time -> 99 ms]
D/MainFragment: [@Observable#getPermissionsObservable ->  :: @ObserveOn -> main]
D/MainFragment: [@Observable#getPermissionsObservable -> onUnsubscribe()]

The first request in the fragment happens in onActivityCreated(). After debugging, I saw the problem was that onDestroy() of the ShadowActivity from the first try is called before onRequestPermissionsResult() of the second Activity, therefore calling onCompleted() on all subjects.

D/RxPermissions: Requesting permissions android.permission.ACCESS_FINE_LOCATION
D/RxPermissions: startShadowActivity android.permission.ACCESS_FINE_LOCATION
D/RxPermissions: onRequestPermissionsResult  android.permission.ACCESS_FINE_LOCATION
D/RxPermissions: Requesting permissions android.permission.ACCESS_FINE_LOCATION
D/RxPermissions: startShadowActivity android.permission.ACCESS_FINE_LOCATION
D/RxPermissions: onDestroy
D/RxPermissions: onRequestPermissionsResult  android.permission.ACCESS_FINE_LOCATION
D/RxPermissions: onDestroy

However, this should not happen, since the Activity is started with FLAG_ACTIVITY_NEW_TASK, which indicates that only one Activity instance can exist at a time. The correct framework behavior would be to call onNewIntent() in this case. In my case, a new ShadowActivity instance is created and its onCreate() is called before onDestroy() of the old ShadowActivity. This seems to be some sort of Android framework bug. I tried adapting the sample app with a similar use of RxPermissions, but there I couldn’t reproduce this behaviour.

Removing the onDestroy() callback in RxPermissions class solves the issue, but I’m not sure if this could lead to problems with configuration changes (see pull request #14, where this was added). However, in normal cases, removing onDestroy() should not be a problem, because subjects are removed in the onRequestPermissionsResult() callback anyway.

Release date expectations

Due to the popularity of this amazing project I would like to know what the expected release date could be for a stable (production proof) version.

Support @RequiresPermission lint

Are there any plans on supporting @RequiresPermission? For instance I have the following code

final Observable<Void> trigger = RxView.clicks(fab);
rxPermissions.request(trigger, Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe(granted -> {
    if (granted) {
        takePicture();
    } else {
        final View rootView = findViewById(R.id.coordinator_layout);
        Snackbar.make(rootView, R.string.permission_denied, Snackbar.LENGTH_LONG).show();
    }
}, t -> VNTLog.e("Activity", t));

and takePicture looks like this:

@RequiresPermission(allOf = { Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA })
private void takePicture() {
// Some code
}

I get an error saying that I should check the permissions when I call takePicture. I'm not even sure whether there is actually a way of fixing that from your side (the library) since you'll call checkPermission. I just want to point it out however.

The permission dialog will not show again

Reproduce steps:
The situation is like this:
When requesting one permission, the dialog shows.
Then do not choose ALLOW nor DENY, keep the dialog showing and background the app.
Open a deep link to restart the app. the permission dialog gone.
Then request the same permission in the first step, the permission dialog will not show, nothing happens at all.

Bug reason:
Because ShadowActivity in RxPermissions is in another task, when opening deep link, we open activity in original task. So the dialog is gone.
When we request same permission next time, the mSubjects still holds the permission so RxPermissions does not start shadow activity again.
Actually the ShadowActivity is still alive but we can not see it.

got exception and than crash

at rx.internal.util.ScalarSynchronousObservable.create(ScalarSynchronousObservable.java:68)
at rx.Observable.just(Observable.java:1575)
at com.tbruyelle.rxpermissions.RxPermissions.request(RxPermissions.java:125)

Crash on rotation

Hey there,

First of all nice work. Sadly I have to say that your solution currently does not work with rotation changes. Simply press "Enable Camera", rotate your device and press "DENY" on the popup. This will result in the following crash:

 "09-30 23:42:06.090  31948-31948/com.tbruyelle.rxpermissions.sample E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.tbruyelle.rxpermissions.sample, PID: 31948
    java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=463403621, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.tbruyelle.rxpermissions.sample/com.tbruyelle.rxpermissions.sample.MainActivity}: java.lang.IllegalStateException: RxPermission.onRequestPermissionsResult invoked but didn't find the corresponding permission request.
            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: java.lang.IllegalStateException: RxPermission.onRequestPermissionsResult invoked but didn't find the corresponding permission request.
            at com.tbruyelle.rxpermissions.RxPermissions.onRequestPermissionsResult(RxPermissions.java:123)
            at com.tbruyelle.rxpermissions.sample.MainActivity.onRequestPermissionsResult(MainActivity.java:36)
            at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6553)
            at android.app.Activity.dispatchActivityResult(Activity.java:6432)
            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)

Do you have any ideas how to tackle this problem?

Why not using headless fragment for catching the result?

Hey there,

nice idea with this library, but why adding a new (shadow)activity to the stack all the time? You could use a headless fragment instead. This has multiple advantages:

  • No additional activities on stack
  • No additional activity in the manifest

NoSuchMethodError on Android 4.3.1

Hi everyone.
Have
java.lang.NoSuchMethodError:Lcom/tbruyelle/rxpermissions/ShadowActivity;.requestPermissions
on Batmobile XT320. Any idea how to prevent this kind of error?

default

Runtime Permission Denied

Hi,

If user has granted a specific permission to the app and while the application is running, user goes and revoke the permission from settings and just launch the app from the recent applications, Android OS by default restarts the activity and this is making my application crash or showing weird behavior. Does this library cover this issue? Please help.

Any updates?

Maybe we need to override functional like OnShowRationale and OnNeverAskAgain?

java.lang.IllegalStateException: RxPermissions.onRequestPermissionsResult invoked but didn't find the corresponding permission request.

One of my activities asks for camera permission on trigger (button click)
After following steps, exception is thrown:

  1. user presses button and shadow activity with dialog that asks for permission is shown
  2. user goes to settings and revoke some other permission
  3. user reopens app - shadow activity with dialog is still there
  4. user allows/denies permission and app crashes with exception

from what I saw in code:
RxPermissions.request_() where mSubjects is filled is called before permission is revoked by user

After user revoked permission app is recreated in new process and mSubjects is empty - therefore exception is thrown in RxPermissions.onRequestPermissionsResult()

Can you please fix this or suggest a workaround?

unfortunately package installer has stopped

When I try the project sample it work but not when I create my own sample ❓

I don't why I got this message "unfortunately package installer has stopped" when I try to run the project.

build.gradle

dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])
  testCompile 'junit:junit:4.12'
  compile 'com.android.support:appcompat-v7:24.1.1'
  compile 'com.jakewharton.rxbinding:rxbinding:0.4.0'
  compile 'com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar'

  compile 'com.android.support:support-v4:24.1.1'
}

Activity.java

private RxPermissions rxPermissions;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);
    rxPermissions = RxPermissions.getInstance(this);
    rxPermissions.setLogging(true);



    final TextView textView = (TextView) findViewById(R.id.text);
    EditText name = (EditText) findViewById(R.id.name);
    Button button = (Button) findViewById(R.id.button);

    RxView.clicks(button)
        .compose(rxPermissions.ensure(Manifest.permission.SEND_SMS))
        .subscribe(new Action1<Boolean>() {
          @Override public void call(Boolean aBoolean) {
            Log.d(TAG, "Permission granted : " + aBoolean);
          }
        });

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.abdellahselassi.myapplication" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity android:name=".MainActivityTest" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

A way to avoid `trigger`

Since passing a trigger is somewhat different from Rx's idea, I've found a more beautiful way to achieve it by using RxJava's compose method:

private Observable.Transformer<Void, Boolean> ensurePermissions(@NonNull String... permissions) {
    return source -> RxPermissions.getInstance(this).request(source, permissions);
}
menuItemClicks(R.id.share)
        .compose(bindToLifecycle())
        .compose(ensurePermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE))
        // ......

Please consider this more intuitive style.

Result is lost after Denying (DNKA on)

Hello,

Looks like there is one more issue, when the result of permission request is lost. Steps to reproduce it with the sample app:

  1. Turn "Do not keep activities" on.
  2. Open the sample app, press "Enable camera".
  3. See the permission request dialog, don't press anything.
  4. Fold the app up.
  5. Retrieve the app from the recent apps.
  6. Click "Deny" (don't check "Never ask again").
  7. Press "Enable camera" again.
    Expected result: Permission request is done again, system dialog shown.
    Actual result: Nothing happens.

This one did I not observe in the 0.5.x version.

Request READ_EXTERNAL_STORAGE will fail on pre 4.1 devices

Since the READ_EXTERNAL_STORAGE was introduced with Android 4.1 the call to ActivityCompat.requestPermissions will return that the permission is denied on devices running Android 4.0 or below.

More information can be found here: https://commonsware.com/blog/2015/11/09/you-cannot-hold-nonexistent-permissions.html

In any case this library should return true when I call .request(Manifest.permission.READ_EXTERNAL_STORAGE) on devices below 4.1.

When asked `Manifest.permission.READ_CONTACTS` always return true

When i use RxPermissions in my devices(HTC desire 816 Android 6.0):

RxView.clicks(bt1)
            .compose(RxPermissions.getInstance(getApplicationContext())
                    .ensure(Manifest.permission.READ_CONTACTS))
            .subscribe(new Action1<Boolean>() {
                @Override
                public void call(Boolean aBoolean) {
                    if (aBoolean) {
                        List<ContactBean> contacts = ContactUtils.getContacts(getApplicationContext());
                        Log.i(TAG, "call: " + contacts);
                    } else {
                        Toast.makeText(getApplicationContext(), "REFUSED!", Toast.LENGTH_SHORT).show();
                    }
                    Log.i(TAG, "callxx: " + aBoolean);

                }
            }, new Action1<Throwable>() {
                @Override
                public void call(Throwable throwable) {
                    Log.e(TAG, "callxxx: ", throwable);
                }
            });

I'm confused that these codes always return true even if i chose Deny in the dialog !
What‘s wrong with these codes ?

Fatal Exception : unable resume activity

i have trying implement in my apps, but its error and here are the logcat (Nexus 6 - Android 6.0)

Fatal Exception: java.lang.RuntimeException: Unable to resume activity {kulina.id/com.tbruyelle.rxpermissions.ShadowActivity}: java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=42, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {kulina.id/com.tbruyelle.rxpermissions.ShadowActivity}: java.lang.IllegalStateException: RxPermissions.onRequestPermissionsResult invoked but didn't find the corresponding permission request.
       at android.app.ActivityThread.performResumeActivity(ActivityThread.java)
       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java)
       at android.app.ActivityThread.-wrap11(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java)
       at android.os.Handler.dispatchMessage(Handler.java)
       at android.os.Looper.loop(Looper.java)
       at android.app.ActivityThread.main(ActivityThread.java)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java)
Caused by java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=42, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {kulina.id/com.tbruyelle.rxpermissions.ShadowActivity}: java.lang.IllegalStateException: RxPermissions.onRequestPermissionsResult invoked but didn't find the corresponding permission request.
       at android.app.ActivityThread.deliverResults(ActivityThread.java)
       at android.app.ActivityThread.performResumeActivity(ActivityThread.java)
       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java)
       at android.app.ActivityThread.-wrap11(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java)
       at android.os.Handler.dispatchMessage(Handler.java)
       at android.os.Looper.loop(Looper.java)
       at android.app.ActivityThread.main(ActivityThread.java)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java)
Caused by java.lang.IllegalStateException: RxPermissions.onRequestPermissionsResult invoked but didn't find the corresponding permission request.
       at com.tbruyelle.rxpermissions.RxPermissions.onRequestPermissionsResult(RxPermissions.java)
       at com.tbruyelle.rxpermissions.ShadowActivity.onRequestPermissionsResult(ShadowActivity.java)
       at android.app.Activity.dispatchRequestPermissionsResult(Activity.java)
       at android.app.Activity.dispatchActivityResult(Activity.java)
       at android.app.ActivityThread.deliverResults(ActivityThread.java)
       at android.app.ActivityThread.performResumeActivity(ActivityThread.java)
       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java)
       at android.app.ActivityThread.-wrap11(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java)
       at android.os.Handler.dispatchMessage(Handler.java)
       at android.os.Looper.loop(Looper.java)
       at android.app.ActivityThread.main(ActivityThread.java)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java)

and here are my code

if (Build.VERSION.SDK_INT >= 23) {
      RxPermissions.getInstance(this)
          .request(Manifest.permission.INTERNET, Manifest.permission.ACCESS_NETWORK_STATE,
              Manifest.permission.WAKE_LOCK, Manifest.permission.WRITE_EXTERNAL_STORAGE,
              Manifest.permission.GET_ACCOUNTS, Manifest.permission.RECEIVE_SMS,
              Manifest.permission.READ_SMS, Manifest.permission.READ_CONTACTS,
              Manifest.permission.READ_LOGS, Manifest.permission.ACCESS_COARSE_LOCATION,
              Manifest.permission.RECORD_AUDIO, Manifest.permission.MODIFY_AUDIO_SETTINGS,
              Manifest.permission.READ_PHONE_STATE, Manifest.permission.SYSTEM_ALERT_WINDOW)
          .subscribe(granted -> {
            if (granted) {
              // do something
            } else {
              Toast.makeText(SplashActivity.this, "some permission denied by user",
                  Toast.LENGTH_SHORT).show();
            }
          });
    } else {
     // do something
    }

extend approach to support OnActivityResult

Should probably be as a seperate library/maybe base library that this one also uses.

Dealing with OnActivityResult is a trickier case.

Example scenario:

  1. User clicks on "get google login token" button.
  2. Play services isn't updated -> out of app -> OnActivityResult (.. not even sure you get an OnActivityResult here actually.. Would need to recheck this in onResume...)
  3. User needs to select account -> out of app -> OnActivityResult
  4. User needs to authorize the scopes -> out of app -> OnActivityResult
  5. Now we have a valid google client, and need to trigger get token (on another thread).

For most of them I think we could just restart the entire flow (running the code again will just skip that step anyway). In order to trigger any action you'll need to get a valid googleApiClient, which is also an async request.

Lets say each request has an identifier. We would have to store all OnActivityResult results to SavedInstanceState as long as that identifier isn't completed/unsubscribed. That way when for example 3-SelectUserAccountOperator runs it'll check if we already have a result, if we do we can just passthrough.

Testing problem granted always true

Hello,
I am trying to test each branch of granted/not granted permissions but with I don't know should approach this because I always get granted == true.

public void onCreate(Bundle savedInstanceState) {
RxPermissions.getInstance(getActivity())
                .request(Manifest.permission.READ_EXTERNAL_STORAGE)
                .subscribe(new Action1<Boolean>() {
                    @Override
                    public void call(Boolean granted) {
                        if (granted) {
                            injectComponent();
                        } else {
                            // Oups permission denied
                            getActivity().onBackPressed();
                        }
                    }
                });
}

Test

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class,sdk = 23)
public class SelfieFragmentTest
    @Mock
    Context mContext;
    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        Mockito.doReturn(mContext).when(mContext).getApplicationContext();
        RxPermissions.getInstance(mContext);
        Mockito.doReturn(false).when(Mockito.spy(RxPermissions.getInstance(mContext))).isGranted(anyString());
        Mockito.doReturn(Observable.just(false)).when(Mockito.spy(RxPermissions.getInstance(mContext))).request(anyString());
    }
}  

I mocked the spy's isGranted() and request() to always return negatives but then when I request some permission it always returns positives (granted = true) and it goes to on the first branch where I do injection. I also set the sdk 23 in the testing class and in gradle but still no luck.

Thank you for any help !

Update sample with non-lambdas

The sample app and the sample code in description uses Lambda, which many people aren't aware of (the syntax) nor is supported by Android so please add a sample without Lambdas so we can understand how to use it without Lambdas

SDK 23 not work for WRITE_SETTINGS

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.System.canWrite(activity)) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
                intent.setData(Uri.parse("package:" + activity.getPackageName()));
                activity.startActivity(intent);
            }
        }

should like this...

Why not push to Maven central ?

I was wondering what the reasoning is behind not putting this on Maven central or jcenter? I keep forgetting to add the special maven repository in my apps.

CRASH: Fold the app up when dialog is showing (dnka off)

Hello,

Please note that the last version of the library (0.6.1) produces crash with the following steps (for the sample app):
0. "Do not keep activities" OFF

  1. Open the sample app.
  2. Press "Enable camera"
  3. While the dialog is on the screen, fold the app up.
  4. Retrieve the app from the recent apps.
  5. Press "Allow".
    Actual result: App crashes.

The log is as follows:
03-29 12:33:01.757 1921-1921/com.tbruyelle.rxpermissions.sample E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.tbruyelle.rxpermissions.sample, PID: 1921
java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=42, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.tbruyelle.rxpermissions.sample/com.tbruyelle.rxpermissions.ShadowActivity}: java.lang.IllegalStateException: RxPermissions.onRequestPermissionsResult invoked but didn't find the corresponding permission request.
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: java.lang.IllegalStateException: RxPermissions.onRequestPermissionsResult invoked but didn't find the corresponding permission request.
at com.tbruyelle.rxpermissions.RxPermissions.onRequestPermissionsResult(RxPermissions.java:302)
at com.tbruyelle.rxpermissions.ShadowActivity.onRequestPermissionsResult(ShadowActivity.java:32)
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) 

Code inside granted doesn't executed for the second time

Hi,

I've created a method which uses Smart location lib to get the user location.
Now I'm calling that method inside RxPermissions subscriber--> granted. So for the first time it asks for the permission and works fine but when the user comes again and permission is already granted then it skips that block and that code never gets executed.
Any callback that the user has selected "Never" for the permission.

Here is some code:

RxPermissions.getInstance(this).request(Manifest.permission.ACCESS_FINE_LOCATION)
.subscribe(granted -> {
if (granted) {
getUserLocation();
} else {
Logger.snackBar(findViewById(android.R.id.content), "Permission Denied");
}
});

getUserLocation() is the one where permission is required. This method is executed only for the first time when I allow and never called second time as it never goes inside if else.

Moreover do you have any methods (like other locations libs does) where on deny we show a dialog of snackbar message with Settings link so enable it from there.
Actually I'm new with permissions so looking out for some support.

And is there anyway that once the user denies and we show him a dialog with explanation for the permission and if he clicks "Ok" show him the permission dialog again.

Trigger view is not existing in any initialisation event

I have a view based activity and depending on the current state, I change my menu in the toolbar while activity is shown. This means, I can not create a view click observable in an init event, because the view may not be existing...

Any idea how to solve that problem?

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.