0

I have a headless fragment to ask permissions in run-time for Marshmallow devices.

public class ReadContactPermissionHelper extends Fragment {
    private static final int REQUEST_READ_CONTACT_PERMISSION = 9001;
    public static final String TAG = "ReadContactPermission";

    private Activity activity;

    private static boolean isReadContactPermissionDenied;
    private OnReadContactPermissionCallback mCallback;

    public static ReadContactPermissionHelper newInstance() {
        return new ReadContactPermissionHelper();
    }

    public ReadContactPermissionHelper() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    @TargetApi(23)
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        onAttachToContext(context);
    }

    @SuppressWarnings("deprecation")
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (Build.VERSION.SDK_INT < 23) {
            onAttachToContext(activity);
        }
    }

    protected void onAttachToContext(Context context) {
        if (context instanceof Activity) {
            activity = (Activity) context;
            if (activity instanceof OnReadContactPermissionCallback) {
                mCallback = (OnReadContactPermissionCallback) activity;
            } else {
                throw new IllegalArgumentException("Activity must implement ReadContactPermissionCallback");
            }
        }
    }

    public void checkReadContactPermission() {
        if (PermissionUtil.hasSelfPermission(activity, new String[]{Manifest.permission.READ_CONTACTS})) {
            mCallback.onReadContactPermissionGranted();
        } else {
            if (!isReadContactPermissionDenied) {
                requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_READ_CONTACT_PERMISSION);
            }
        }
    }

    public static void setReadContactPermissionDenied(boolean cameraMicPermissionDenied) {
        isReadContactPermissionDenied = cameraMicPermissionDenied;
    }

    public static boolean isReadContactPermissionDenied() {
        return isReadContactPermissionDenied;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                           int[] grantResults) {

        if (requestCode == REQUEST_READ_CONTACT_PERMISSION) {
            if (PermissionUtil.verifyPermissions(grantResults)) {
                ReadContactPermissionHelper.setReadContactPermissionDenied(false);
                mCallback.onReadContactPermissionGranted();
            } else {
                ReadContactPermissionHelper.setReadContactPermissionDenied(true);
                mCallback.onReadContactPermissionDenied();
            }

        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    public interface OnReadContactPermissionCallback {
        void onReadContactPermissionGranted();
        void onReadContactPermissionDenied();
    }
}

And in activity where I require this permission, I'm calling checkReadContactPermission in headless fragment which then does the permission check task.

In activity I have following -

ReadContactPermissionHelper mReadContactPermissionHelper = (ReadContactPermissionHelper) getSupportFragmentManager().findFragmentByTag(ReadContactPermissionHelper.TAG);
        if (mReadContactPermissionHelper == null) {
            mReadContactPermissionHelper = ReadContactPermissionHelper.newInstance();
            getSupportFragmentManager().beginTransaction()
                    .add(mReadContactPermissionHelper, ReadContactPermissionHelper.TAG)
                    .commit();
        }
mReadContactPermissionHelper.checkReadContactPermission();

However, calling checkReadContactPermission() is crashing the app as Activity is null while checking the permission -

Log

FATAL EXCEPTION: main
Process: com.sachingutte.cardmeup, PID: 12087
java.lang.RuntimeException: Unable to start activity com.sachingutte.example{com.sachingutte.example/com.sachingutte.example.AddPhoneContactActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.app.Activity.checkSelfPermission(java.lang.String)' on a null object reference
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
  at android.app.ActivityThread.-wrap11(ActivityThread.java)
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
  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.NullPointerException: Attempt to invoke virtual method 'int android.app.Activity.checkSelfPermission(java.lang.String)' on a null object reference
  at com.sachingutte.example.helpers.PermissionUtil.hasSelfPermission(PermissionUtil.java:60)
  at com.sachingutte.example.helpers.ReadContactPermissionHelper.checkReadContactPermission(ReadContactPermissionHelper.java:69)
  at com.sachingutte.example.AddPhoneContactActivity.onCreate(AddPhoneContactActivity.java:151)
  at android.app.Activity.performCreate(Activity.java:6251)
  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
  at android.app.ActivityThread.-wrap11(ActivityThread.java) 
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
  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) 

So problem is when PermissionUtil.hasSelfPermission(activity, new String[]{Manifest.permission.READ_CONTACTS})) is called, null activity is being passed. onAttach method is not getting called.

SachinGutte
  • 6,947
  • 5
  • 35
  • 58
  • 3
    `commit()` is asynchronous. The fragment will not be attached by the time `commit()` returns. I am unclear as to why you are using a headless fragment here in general. – CommonsWare May 26 '16 at 18:41
  • @CommonsWare actually I'm using to save some time going through permission checks in each activity. There is going to be a few activities where I need this permission. Is using headless fragment not suitable for these kind of operations? – SachinGutte May 26 '16 at 18:45
  • Not if you want to check the permission immediately. Reuse is fine; I do not see where a headless fragment is a benefit over some other sort of helper class, though. – CommonsWare May 26 '16 at 18:46
  • @CommonsWare I was using base activity before but gradually it became overhead to manage. Any way I could use this approach if I need permissions immediately. Or I could drop this and go for other option ? – SachinGutte May 26 '16 at 18:51
  • You could postpone requesting the permissions until inside `onAttach()`, I guess. – CommonsWare May 26 '16 at 18:52
  • @CommonsWare Maybe I can use callback here. Just a callback method telling activity that fragment is ready and proceed to the next flow. – SachinGutte May 26 '16 at 18:54

0 Answers0