From e335ca0c144bdfcd14a44b5acd0968ae2e51046b Mon Sep 17 00:00:00 2001 From: John Shelley Date: Tue, 6 Dec 2016 12:29:39 -0800 Subject: [PATCH] Android - Fix Overlay for Marshmallow 23+ Summary: Currently any React Native apps that target API 23 or greater will crash on the first initial debug/dev build due to the overlay permission. Sadly there isn't a concrete "request permission" baked into the Marshmallow permission system. However, we can launch the overlay screen without starting the react app and once its turned on start the app. - https://github.com/facebook/react-native/issues/10454 - targetSdkVersion 23 lead crash / App crash for targeting 23+ - https://github.com/facebook/react-native/pull/10479 - Add the overlay permission information / Larger discussion around targeting API 23+ - Intent to Overlay permission goes directly to the app in question, rather then the general full listing of applications. This allows a developer who is not familiar with the system to easily toggle the overlay without getting confused. **Test plan (required)** * Ran UIExplorer App on fresh install with Target 23 ``` cd react-native ./gradlew :Examples:UI Closes https://github.com/facebook/react-native/pull/11316 Differential Revision: D4286351 fbshipit-source-id: 024e97c08c40ee23646dd153794fcde7127b2308 --- .../facebook/react/ReactActivityDelegate.java | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java index 2791564f80c..ef4d7c2052c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactActivityDelegate.java @@ -6,6 +6,7 @@ import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.Settings; @@ -29,6 +30,10 @@ import javax.annotation.Nullable; * class doesn't implement {@link ReactApplication}. */ public class ReactActivityDelegate { + + private final int REQUEST_OVERLAY_PERMISSION_CODE = 1111; + private static final String REDBOX_PERMISSION_GRANTED_MESSAGE = + "Overlay permissions have been granted."; private static final String REDBOX_PERMISSION_MESSAGE = "Overlay permissions needs to be granted in order for react native apps to run in dev mode"; @@ -79,17 +84,19 @@ public class ReactActivityDelegate { } protected void onCreate(Bundle savedInstanceState) { - if (getReactNativeHost().getUseDeveloperSupport() && Build.VERSION.SDK_INT >= 23) { + boolean needsOverlayPermission = false; + if (getReactNativeHost().getUseDeveloperSupport() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // Get permission to show redbox in dev builds. if (!Settings.canDrawOverlays(getContext())) { - Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); - getContext().startActivity(serviceIntent); + needsOverlayPermission = true; + Intent serviceIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getContext().getPackageName())); FLog.w(ReactConstants.TAG, REDBOX_PERMISSION_MESSAGE); Toast.makeText(getContext(), REDBOX_PERMISSION_MESSAGE, Toast.LENGTH_LONG).show(); + ((Activity) getContext()).startActivityForResult(serviceIntent, REQUEST_OVERLAY_PERMISSION_CODE); } } - if (mMainComponentName != null) { + if (mMainComponentName != null && !needsOverlayPermission) { loadApp(mMainComponentName); } mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer(); @@ -140,6 +147,16 @@ public class ReactActivityDelegate { if (getReactNativeHost().hasInstance()) { getReactNativeHost().getReactInstanceManager() .onActivityResult(getPlainActivity(), requestCode, resultCode, data); + } else { + // Did we request overlay permissions? + if (requestCode == REQUEST_OVERLAY_PERMISSION_CODE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (Settings.canDrawOverlays(getContext())) { + if (mMainComponentName != null) { + loadApp(mMainComponentName); + } + Toast.makeText(getContext(), REDBOX_PERMISSION_GRANTED_MESSAGE, Toast.LENGTH_LONG).show(); + } + } } } @@ -191,8 +208,7 @@ public class ReactActivityDelegate { mPermissionsCallback = new Callback() { @Override public void invoke(Object... args) { - if (mPermissionListener != null && - mPermissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults)) { + if (mPermissionListener != null && mPermissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults)) { mPermissionListener = null; } }