summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzafir <zafir@google.com>2015-06-29 00:08:22 -0500
committerJay Wang <jaywang@codeaurora.org>2016-06-02 16:10:01 -0700
commitf6ced59d086a755d6f720600181c023c29d202ca (patch)
tree7633600936f93cebc7e456b3054e97cc2c5b4595
parentdba00aac4e44a91bc55b0aabca9f191d03994edf (diff)
downloadandroid_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.xml10
-rw-r--r--res/values/strings.xml6
-rw-r--r--src/com/android/camera/CameraActivity.java41
-rw-r--r--src/com/android/camera/PermissionsActivity.java167
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();
+ }
+}