diff options
author | zafir <zafir@google.com> | 2015-06-29 00:08:22 -0500 |
---|---|---|
committer | Jay Wang <jaywang@codeaurora.org> | 2016-06-02 16:10:01 -0700 |
commit | f6ced59d086a755d6f720600181c023c29d202ca (patch) | |
tree | 7633600936f93cebc7e456b3054e97cc2c5b4595 | |
parent | dba00aac4e44a91bc55b0aabca9f191d03994edf (diff) | |
download | android_packages_apps_Snap-f6ced59d086a755d6f720600181c023c29d202ca.tar.gz android_packages_apps_Snap-f6ced59d086a755d6f720600181c023c29d202ca.tar.bz2 android_packages_apps_Snap-f6ced59d086a755d6f720600181c023c29d202ca.zip |
Minimum viable Android M runtime permissions handling for H.
Creates new activity for permissions handling: both checking
for permissions and handling error condition when critical
permissions are not present. The reason for creating a
new activity is so the app does not attempt to continue
executing OnCreate, OnResume etc, which opens
the camera while the dialogs are showing. This should
not slow the app down because the permissions activity
will only run when a) the first time the app has
insufficient permissions and b) when a critical
permission is missing and the app needs to shut down.
Bug: 21273463
CRs-Fixed: 1019847
Change-Id: I603acfb3057ba26b9cfa7935eb4cb24b5d547cb5
(cherry picked from commit ad44cda82fe6ec5ee090115129223c6314f9e1bb)
-rw-r--r-- | AndroidManifest.xml | 10 | ||||
-rw-r--r-- | res/values/strings.xml | 6 | ||||
-rw-r--r-- | src/com/android/camera/CameraActivity.java | 41 | ||||
-rw-r--r-- | src/com/android/camera/PermissionsActivity.java | 167 |
4 files changed, 223 insertions, 1 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index ac727e2a2..12a86bb9b 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -20,7 +20,6 @@ <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> <uses-permission android:name="android.permission.NFC" /> - <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> @@ -83,6 +82,15 @@ android:resource="@layout/keyguard_widget" /> </activity> + <activity + android:name="com.android.camera.PermissionsActivity" + android:label="@string/app_name" + android:parentActivityName="com.android.camera.CameraActivity" > + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value="com.android.camera.CameraActivity" /> + </activity> + <activity-alias android:name="com.android.camera.CameraLauncher" android:icon="@mipmap/ic_launcher_camera" diff --git a/res/values/strings.xml b/res/values/strings.xml index 2b06e257f..898329a7f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -171,6 +171,12 @@ <!-- message for the dialog showing the camera is disabled because of security policies. Camera cannot be used. --> <string name="camera_disabled">Camera has been disabled because of security policies.</string> + <!-- message for the dialog showing that the app does not have sufficient permissions [CHAR LIMIT=NONE] --> + <string name="error_permissions">The app does not have critical permissions needed to run. Please check your permissions settings.</string> + + <!-- Dialog "Dismiss" button. Closes the dialog [CHAR LIMIT=12]--> + <string name="dialog_dismiss">Dismiss</string> + <!-- alert to the user to wait for some operation to complete --> <string name="wait">Please wait\u2026</string> diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index fafb40839..5f93bb93e 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -18,6 +18,7 @@ package com.android.camera; import android.view.Display; import android.graphics.Point; +import android.Manifest; import android.animation.Animator; import android.annotation.TargetApi; import android.app.ActionBar; @@ -32,6 +33,7 @@ import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.Cursor; import android.graphics.Bitmap; @@ -144,6 +146,9 @@ public class CameraActivity extends Activity // This string is used for judge start activity from screenoff or not public static final String GESTURE_CAMERA_NAME = "com.android.camera.CameraGestureActivity"; + private static final int PERMISSIONS_ACTIVITY_REQUEST_CODE = 1; + private static final int PERMISSIONS_RESULT_CODE_OK = 0; + private static final int PERMISSIONS_RESULT_CODE_FAILED = 1; /** * Request code from an activity we started that indicated that we do not @@ -220,6 +225,7 @@ public class CameraActivity extends Activity private View mPreviewCover; private FrameLayout mPreviewContentLayout; private boolean mPaused = true; + private boolean mHasCriticalPermissions; private Uri[] mNfcPushUris = new Uri[1]; @@ -1376,6 +1382,7 @@ public class CameraActivity extends Activity @Override public void onCreate(Bundle state) { super.onCreate(state); + checkPermissions(); // Check if this is in the secure camera mode. Intent intent = getIntent(); String action = intent.getAction(); @@ -1613,6 +1620,10 @@ public class CameraActivity extends Activity mIsEditActivityInProgress = false; } else { super.onActivityResult(requestCode, resultCode, data); + // Close the app if critical permissions are missing. + if (requestCode == PERMISSIONS_ACTIVITY_REQUEST_CODE && resultCode == PERMISSIONS_RESULT_CODE_FAILED) { + finish(); + } } } @@ -1623,8 +1634,38 @@ public class CameraActivity extends Activity if (focus) this.setSystemBarsVisibility(false); } + /** + * Checks if any of the needed Android runtime permissions are missing. + * If they are, then launch the permissions activity under one of the following conditions: + * a) The permissions dialogs have not run yet. We will ask for permission only once. + * b) If the missing permissions are critical to the app running, we will display a fatal error dialog. + * Critical permissions are: camera, microphone and storage. The app cannot run without them. + * Non-critical permission is location. + */ + private void checkPermissions() { + + if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED && + checkSelfPermission(Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED && + checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + mHasCriticalPermissions = true; + } else { + mHasCriticalPermissions = false; + } + + if ((checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) || + !mHasCriticalPermissions) { + Intent intent = new Intent(this, PermissionsActivity.class); + startActivityForResult(intent, PERMISSIONS_ACTIVITY_REQUEST_CODE); + } + } + @Override public void onResume() { + if (!mHasCriticalPermissions) { + super.onResume(); + Log.v(TAG, "Missing critical permissions."); + return; + } // Hide action bar first since we are in full screen mode first, and // switch the system UI to lights-out mode. this.setSystemBarsVisibility(false); diff --git a/src/com/android/camera/PermissionsActivity.java b/src/com/android/camera/PermissionsActivity.java new file mode 100644 index 000000000..f2d907c68 --- /dev/null +++ b/src/com/android/camera/PermissionsActivity.java @@ -0,0 +1,167 @@ +package com.android.camera; + +import android.Manifest; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.pm.PackageManager; +import android.os.Bundle; +import org.codeaurora.snapcam.R; + +/** + * Activity that shows permissions request dialogs and handles lack of critical permissions. + */ +public class PermissionsActivity extends Activity { + private static final String TAG = "PermissionsActivity"; + + private static int PERMISSION_REQUEST_CODE = 1; + private static int RESULT_CODE_OK = 0; + private static int RESULT_CODE_FAILED = 1; + + private int mIndexPermissionRequestCamera; + private int mIndexPermissionRequestMicrophone; + private int mIndexPermissionRequestLocation; + private int mIndexPermissionRequestStorage; + private boolean mShouldRequestCameraPermission; + private boolean mShouldRequestMicrophonePermission; + private boolean mShouldRequestLocationPermission; + private boolean mShouldRequestStoragePermission; + private int mNumPermissionsToRequest; + private boolean mFlagHasCameraPermission; + private boolean mFlagHasMicrophonePermission; + private boolean mFlagHasStoragePermission; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + protected void onResume() { + super.onResume(); + mNumPermissionsToRequest = 0; + checkPermissions(); + } + + private void checkPermissions() { + if (checkSelfPermission(Manifest.permission.CAMERA) + != PackageManager.PERMISSION_GRANTED) { + mNumPermissionsToRequest++; + mShouldRequestCameraPermission = true; + } else { + mFlagHasCameraPermission = true; + } + + if (checkSelfPermission(Manifest.permission.RECORD_AUDIO) + != PackageManager.PERMISSION_GRANTED) { + mNumPermissionsToRequest++; + mShouldRequestMicrophonePermission = true; + } else { + mFlagHasMicrophonePermission = true; + } + + if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + mNumPermissionsToRequest++; + mShouldRequestStoragePermission = true; + } else { + mFlagHasStoragePermission = true; + } + + if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) + != PackageManager.PERMISSION_GRANTED) { + mNumPermissionsToRequest++; + mShouldRequestLocationPermission = true; + } + + if (mNumPermissionsToRequest != 0) { + buildPermissionsRequest(); + } else { + handlePermissionsSuccess(); + } + } + + private void buildPermissionsRequest() { + String[] permissionsToRequest = new String[mNumPermissionsToRequest]; + int permissionsRequestIndex = 0; + + if (mShouldRequestCameraPermission) { + permissionsToRequest[permissionsRequestIndex] = Manifest.permission.CAMERA; + mIndexPermissionRequestCamera = permissionsRequestIndex; + permissionsRequestIndex++; + } + if (mShouldRequestMicrophonePermission) { + permissionsToRequest[permissionsRequestIndex] = Manifest.permission.RECORD_AUDIO; + mIndexPermissionRequestMicrophone = permissionsRequestIndex; + permissionsRequestIndex++; + } + if (mShouldRequestStoragePermission) { + permissionsToRequest[permissionsRequestIndex] = Manifest.permission.READ_EXTERNAL_STORAGE; + mIndexPermissionRequestStorage = permissionsRequestIndex; + permissionsRequestIndex++; + } + if (mShouldRequestLocationPermission) { + permissionsToRequest[permissionsRequestIndex] = Manifest.permission.ACCESS_COARSE_LOCATION; + mIndexPermissionRequestLocation = permissionsRequestIndex; + } + + requestPermissions(permissionsToRequest, PERMISSION_REQUEST_CODE); + } + + @Override + public void onRequestPermissionsResult(int requestCode, + String permissions[], int[] grantResults) { + + if (mShouldRequestCameraPermission) { + if (grantResults[mIndexPermissionRequestCamera] == PackageManager.PERMISSION_GRANTED) { + mFlagHasCameraPermission = true; + } else { + handlePermissionsFailure(); + } + } + if (mShouldRequestMicrophonePermission) { + if (grantResults[mIndexPermissionRequestMicrophone] == PackageManager.PERMISSION_GRANTED) { + mFlagHasMicrophonePermission = true; + } else { + handlePermissionsFailure(); + } + } + if (mShouldRequestStoragePermission) { + if (grantResults[mIndexPermissionRequestStorage] == PackageManager.PERMISSION_GRANTED) { + mFlagHasStoragePermission = true; + } else { + handlePermissionsFailure(); + } + } + + if (mShouldRequestLocationPermission) { + if (grantResults[mIndexPermissionRequestLocation] == PackageManager.PERMISSION_GRANTED) { + // Do nothing + } else { + // Do nothing + } + } + + if (mFlagHasCameraPermission && mFlagHasMicrophonePermission && mFlagHasStoragePermission) { + handlePermissionsSuccess(); + } + } + + private void handlePermissionsSuccess() { + setResult(RESULT_CODE_OK, null); + finish(); + } + + private void handlePermissionsFailure() { + new AlertDialog.Builder(this).setTitle(getResources().getString(R.string.camera_error_title)) + .setMessage(getResources().getString(R.string.error_permissions)) + .setPositiveButton(getResources().getString(R.string.dialog_dismiss), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + setResult(RESULT_CODE_FAILED, null); + finish(); + } + }) + .show(); + } +} |