Skip to content

Commit

Permalink
Android - Fix Overlay for Marshmallow 23+
Browse files Browse the repository at this point in the history
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.

 - #10454 - targetSdkVersion 23 lead crash / App crash for targeting 23+
 - #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 #11316

Differential Revision: D4286351

fbshipit-source-id: 024e97c08c40ee23646dd153794fcde7127b2308
  • Loading branch information
jpshelley authored and Martin Konicek committed Dec 12, 2016
1 parent fd144a2 commit e335ca0
Showing 1 changed file with 22 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
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;
Expand All @@ -29,6 +30,10 @@
* 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";

Expand Down Expand Up @@ -79,17 +84,19 @@ public ReactInstanceManager getReactInstanceManager() {
}

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();
Expand Down Expand Up @@ -140,6 +147,16 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
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();
}
}
}
}

Expand Down Expand Up @@ -191,8 +208,7 @@ public void onRequestPermissionsResult(
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;
}
}
Expand Down

0 comments on commit e335ca0

Please sign in to comment.