aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Rashidi <paulrashidi@google.com>2015-08-13 23:16:00 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-08-13 23:16:00 +0000
commit0a61c896adaf8f1583f6a7c565d2efb2b2c3de41 (patch)
tree32d78165ba25f7dd663cf23410c18471b1aceda4
parentdb846a9915f586657bbda28a75ba0a7556f088c2 (diff)
parentd4406c89a0e71f523c4b34ea34fd61ebb4e98626 (diff)
downloadandroid-0a61c896adaf8f1583f6a7c565d2efb2b2c3de41.tar.gz
Merge "Updating sample to use Android M permissions model." into mnc-dev
-rw-r--r--media/HdrViewfinder/Application/src/main/AndroidManifest.xml9
-rw-r--r--media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/CameraOps.java2
-rw-r--r--media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/HdrViewfinderActivity.java283
-rw-r--r--media/HdrViewfinder/Application/src/main/res/layout/main.xml8
-rw-r--r--media/HdrViewfinder/Application/src/main/res/values/strings.xml8
-rw-r--r--media/HdrViewfinder/template-params.xml2
6 files changed, 231 insertions, 81 deletions
diff --git a/media/HdrViewfinder/Application/src/main/AndroidManifest.xml b/media/HdrViewfinder/Application/src/main/AndroidManifest.xml
index 772b7dfd..63066f6d 100644
--- a/media/HdrViewfinder/Application/src/main/AndroidManifest.xml
+++ b/media/HdrViewfinder/Application/src/main/AndroidManifest.xml
@@ -20,10 +20,6 @@
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="21"
- android:targetSdkVersion="21"/>
-
<uses-feature android:name="android.hardware.camera"/>
<uses-feature
android:name="android.hardware.camera.front"
@@ -31,8 +27,6 @@
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
@@ -43,7 +37,8 @@
<activity
android:name=".HdrViewfinderActivity"
android:label="@string/app_name"
- android:screenOrientation="landscape">
+ android:screenOrientation="landscape"
+ android:theme="@style/Theme.AppCompat.Light">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
diff --git a/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/CameraOps.java b/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/CameraOps.java
index 5769760b..173ef08e 100644
--- a/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/CameraOps.java
+++ b/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/CameraOps.java
@@ -78,7 +78,7 @@ public class CameraOps {
}
/**
- * Open the first backfacing camera listed by the camera manager.
+ * Open the first back-facing camera listed by the camera manager.
* Displays a dialog if it cannot open a camera.
*/
public void openCamera(final String cameraId) {
diff --git a/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/HdrViewfinderActivity.java b/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/HdrViewfinderActivity.java
index 79f1bb61..ca49ea0b 100644
--- a/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/HdrViewfinderActivity.java
+++ b/media/HdrViewfinder/Application/src/main/java/com/example/android/hdrviewfinder/HdrViewfinderActivity.java
@@ -16,7 +16,9 @@
package com.example.android.hdrviewfinder;
-import android.app.Activity;
+import android.Manifest;
+import android.content.Intent;
+import android.content.pm.PackageManager;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
@@ -26,10 +28,16 @@ import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.provider.Settings;
import android.renderscript.RenderScript;
+import android.support.annotation.NonNull;
+import android.support.design.widget.Snackbar;
+import android.support.v4.app.ActivityCompat;
+import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.util.Size;
import android.view.GestureDetector;
@@ -76,19 +84,26 @@ import java.util.List;
* Android {@link android.view.Surface} class, which allows for zero-copy transport of large
* buffers between processes and subsystems.</p>
*/
-public class HdrViewfinderActivity extends Activity implements
+public class HdrViewfinderActivity extends AppCompatActivity implements
SurfaceHolder.Callback, CameraOps.ErrorDisplayer, CameraOps.CameraReadyListener {
private static final String TAG = "HdrViewfinderDemo";
private static final String FRAGMENT_DIALOG = "dialog";
+ private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
+
/**
* View for the camera preview.
*/
private FixedAspectSurfaceView mPreviewView;
/**
+ * Root view of this activity.
+ */
+ private View rootView;
+
+ /**
* This shows the current mode of the app.
*/
private TextView mModeText;
@@ -132,6 +147,8 @@ public class HdrViewfinderActivity extends Activity implements
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
+ rootView = findViewById(R.id.panels);
+
mPreviewView = (FixedAspectSurfaceView) findViewById(R.id.preview);
mPreviewView.getHolder().addCallback(this);
mPreviewView.setGestureListener(this, mViewListener);
@@ -146,23 +163,20 @@ public class HdrViewfinderActivity extends Activity implements
mUiHandler = new Handler(Looper.getMainLooper());
- mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
- mCameraOps = new CameraOps(mCameraManager,
- /*errorDisplayer*/ this,
- /*readyListener*/ this,
- /*readyHandler*/ mUiHandler);
-
- mHdrRequests.add(null);
- mHdrRequests.add(null);
-
mRS = RenderScript.create(this);
+
+ // When permissions are revoked the app is restarted so onCreate is sufficient to check for
+ // permissions core to the Activity's functionality.
+ if (!checkCameraPermissions()) {
+ requestCameraPermissions();
+ } else {
+ findAndOpenCamera();
+ }
}
@Override
protected void onResume() {
super.onResume();
-
- findAndOpenCamera();
}
@Override
@@ -170,7 +184,10 @@ public class HdrViewfinderActivity extends Activity implements
super.onPause();
// Wait until camera is closed to ensure the next application can open it
- mCameraOps.closeCameraAndWait();
+ if (mCameraOps != null) {
+ mCameraOps.closeCameraAndWait();
+ mCameraOps = null;
+ }
}
@Override
@@ -232,7 +249,9 @@ public class HdrViewfinderActivity extends Activity implements
}
};
- // Show help dialog
+ /**
+ * Show help dialogs.
+ */
private View.OnClickListener mHelpButtonListener = new View.OnClickListener() {
public void onClick(View v) {
MessageDialogFragment.newInstance(R.string.help_text)
@@ -240,54 +259,176 @@ public class HdrViewfinderActivity extends Activity implements
}
};
- private void findAndOpenCamera() {
+ /**
+ * Return the current state of the camera permissions.
+ */
+ private boolean checkCameraPermissions() {
+ int permissionState = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
+
+ // Check if the Camera permission is already available.
+ if (permissionState != PackageManager.PERMISSION_GRANTED) {
+ // Camera permission has not been granted.
+ Log.i(TAG, "CAMERA permission has NOT been granted.");
+ return false;
+ } else {
+ // Camera permissions are available.
+ Log.i(TAG, "CAMERA permission has already been granted.");
+ return true;
+ }
+ }
- String errorMessage = "Unknown error";
- boolean foundCamera = false;
- try {
- // Find first back-facing camera that has necessary capability
- String[] cameraIds = mCameraManager.getCameraIdList();
- for (String id : cameraIds) {
- CameraCharacteristics info = mCameraManager.getCameraCharacteristics(id);
- int facing = info.get(CameraCharacteristics.LENS_FACING);
-
- int level = info.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
- boolean hasFullLevel
- = (level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
-
- int[] capabilities = info.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
- int syncLatency = info.get(CameraCharacteristics.SYNC_MAX_LATENCY);
- boolean hasManualControl = hasCapability(capabilities,
- CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
- boolean hasEnoughCapability = hasManualControl &&
- syncLatency == CameraCharacteristics.SYNC_MAX_LATENCY_PER_FRAME_CONTROL;
-
- // All these are guaranteed by
- // CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL, but checking for only
- // the things we care about expands range of devices we can run on
- // We want:
- // - Back-facing camera
- // - Manual sensor control
- // - Per-frame synchronization (so that exposure can be changed every frame)
- if (facing == CameraCharacteristics.LENS_FACING_BACK &&
- (hasFullLevel || hasEnoughCapability)) {
- // Found suitable camera - get info, open, and set up outputs
- mCameraInfo = info;
- mCameraOps.openCamera(id);
- configureSurfaces();
- foundCamera = true;
- break;
- }
- }
- if (!foundCamera) {
- errorMessage = getString(R.string.camera_no_good);
+ /**
+ * Attempt to initialize the camera.
+ */
+ private void initializeCamera() {
+ mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
+ if (mCameraManager != null) {
+ mCameraOps = new CameraOps(mCameraManager,
+ /*errorDisplayer*/ this,
+ /*readyListener*/ this,
+ /*readyHandler*/ mUiHandler);
+
+ mHdrRequests.add(null);
+ mHdrRequests.add(null);
+ } else {
+ Log.e(TAG, "Couldn't initialize the camera");
+ }
+ }
+
+ private void requestCameraPermissions() {
+ boolean shouldProvideRationale =
+ ActivityCompat.shouldShowRequestPermissionRationale(this,
+ Manifest.permission.CAMERA);
+
+ // Provide an additional rationale to the user. This would happen if the user denied the
+ // request previously, but didn't check the "Don't ask again" checkbox.
+ if (shouldProvideRationale) {
+ Log.i(TAG, "Displaying camera permission rationale to provide additional context.");
+ Snackbar.make(rootView, R.string.camera_permission_rationale, Snackbar
+ .LENGTH_INDEFINITE)
+ .setAction(R.string.ok, new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ // Request Camera permission
+ ActivityCompat.requestPermissions(HdrViewfinderActivity.this,
+ new String[]{Manifest.permission.CAMERA},
+ REQUEST_PERMISSIONS_REQUEST_CODE);
+ }
+ })
+ .show();
+ } else {
+ Log.i(TAG, "Requesting camera permission");
+ // Request Camera permission. It's possible this can be auto answered if device policy
+ // sets the permission in a given state or the user denied the permission
+ // previously and checked "Never ask again".
+ ActivityCompat.requestPermissions(HdrViewfinderActivity.this,
+ new String[]{Manifest.permission.CAMERA},
+ REQUEST_PERMISSIONS_REQUEST_CODE);
+ }
+ }
+
+ /**
+ * Callback received when a permissions request has been completed.
+ */
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ Log.i(TAG, "onRequestPermissionResult");
+ if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
+ if (grantResults.length <= 0) {
+ // If user interaction was interrupted, the permission request is cancelled and you
+ // receive empty arrays.
+ Log.i(TAG, "User interaction was cancelled.");
+ } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ // Permission was granted.
+ findAndOpenCamera();
+ } else {
+ // Permission denied.
+
+ // In this Activity we've chosen to notify the user that they
+ // have rejected a core permission for the app since it makes the Activity useless.
+ // We're communicating this message in a Snackbar since this is a sample app, but
+ // core permissions would typically be best requested during a welcome-screen flow.
+
+ // Additionally, it is important to remember that a permission might have been
+ // rejected without asking the user for permission (device policy or "Never ask
+ // again" prompts). Therefore, a user interface affordance is typically implemented
+ // when permissions are denied. Otherwise, your app could appear unresponsive to
+ // touches or interactions which have required permissions.
+ Snackbar.make(rootView, R.string.camera_permission_denied_explanation, Snackbar
+ .LENGTH_INDEFINITE)
+ .setAction(R.string.settings, new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ // Build intent that displays the App settings screen.
+ Intent intent = new Intent();
+ intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ Uri uri = Uri.fromParts("package", BuildConfig.APPLICATION_ID, null);
+ intent.setData(uri);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+ }
+ })
+ .show();
}
- } catch (CameraAccessException e) {
- errorMessage = getErrorString(e);
}
+ }
- if (!foundCamera) {
- showErrorDialog(errorMessage);
+ private void findAndOpenCamera() {
+ boolean cameraPermissions = checkCameraPermissions();
+ if (cameraPermissions) {
+ String errorMessage = "Unknown error";
+ boolean foundCamera = false;
+ initializeCamera();
+ if (cameraPermissions && mCameraOps != null) {
+ try {
+ // Find first back-facing camera that has necessary capability.
+ String[] cameraIds = mCameraManager.getCameraIdList();
+ for (String id : cameraIds) {
+ CameraCharacteristics info = mCameraManager.getCameraCharacteristics(id);
+ int facing = info.get(CameraCharacteristics.LENS_FACING);
+
+ int level = info.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
+ boolean hasFullLevel
+ = (level
+ == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
+
+ int[] capabilities = info
+ .get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+ int syncLatency = info.get(CameraCharacteristics.SYNC_MAX_LATENCY);
+ boolean hasManualControl = hasCapability(capabilities,
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
+ boolean hasEnoughCapability = hasManualControl &&
+ syncLatency
+ == CameraCharacteristics.SYNC_MAX_LATENCY_PER_FRAME_CONTROL;
+
+ // All these are guaranteed by
+ // CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL, but checking
+ // for only the things we care about expands range of devices we can run on.
+ // We want:
+ // - Back-facing camera
+ // - Manual sensor control
+ // - Per-frame synchronization (so that exposure can be changed every frame)
+ if (facing == CameraCharacteristics.LENS_FACING_BACK &&
+ (hasFullLevel || hasEnoughCapability)) {
+ // Found suitable camera - get info, open, and set up outputs
+ mCameraInfo = info;
+ mCameraOps.openCamera(id);
+ configureSurfaces();
+ foundCamera = true;
+ break;
+ }
+ }
+ if (!foundCamera) {
+ errorMessage = getString(R.string.camera_no_good);
+ }
+ } catch (CameraAccessException e) {
+ errorMessage = getErrorString(e);
+ }
+ if (!foundCamera) {
+ showErrorDialog(errorMessage);
+ }
+ }
}
}
@@ -299,23 +440,25 @@ public class HdrViewfinderActivity extends Activity implements
}
private void switchRenderMode(int direction) {
- mRenderMode = (mRenderMode + direction) % 3;
+ if (mCameraOps != null) {
+ mRenderMode = (mRenderMode + direction) % 3;
- mModeText.setText(getResources().getStringArray(R.array.mode_label_array)[mRenderMode]);
+ mModeText.setText(getResources().getStringArray(R.array.mode_label_array)[mRenderMode]);
- if (mProcessor != null) {
- mProcessor.setRenderMode(mRenderMode);
- }
- if (mRenderMode == ViewfinderProcessor.MODE_NORMAL) {
- mCameraOps.setRepeatingRequest(mPreviewRequest,
- mCaptureCallback, mUiHandler);
- } else {
- setHdrBurst();
+ if (mProcessor != null) {
+ mProcessor.setRenderMode(mRenderMode);
+ }
+ if (mRenderMode == ViewfinderProcessor.MODE_NORMAL) {
+ mCameraOps.setRepeatingRequest(mPreviewRequest,
+ mCaptureCallback, mUiHandler);
+ } else {
+ setHdrBurst();
+ }
}
}
/**
- * Configure the surfaceview and RS processing
+ * Configure the surfaceview and RS processing.
*/
private void configureSurfaces() {
// Find a good size for output - largest 16:9 aspect ratio that's less than 720p
diff --git a/media/HdrViewfinder/Application/src/main/res/layout/main.xml b/media/HdrViewfinder/Application/src/main/res/layout/main.xml
index 7507709e..6fe56ef0 100644
--- a/media/HdrViewfinder/Application/src/main/res/layout/main.xml
+++ b/media/HdrViewfinder/Application/src/main/res/layout/main.xml
@@ -15,13 +15,14 @@
limitations under the License.
-->
<LinearLayout
- android:id="@+id/panels"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/panels"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ tools:context="com.example.android.hdrviewfinder.HdrViewfinderActivity">
<com.example.android.hdrviewfinder.FixedAspectSurfaceView
android:id="@+id/preview"
@@ -36,7 +37,8 @@
android:layout_width="0px"
android:layout_height="match_parent"
android:layout_weight="1"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:layout_margin="5dp">
<Button
android:id="@+id/help_button"
diff --git a/media/HdrViewfinder/Application/src/main/res/values/strings.xml b/media/HdrViewfinder/Application/src/main/res/values/strings.xml
index 21838d54..d910ab1a 100644
--- a/media/HdrViewfinder/Application/src/main/res/values/strings.xml
+++ b/media/HdrViewfinder/Application/src/main/res/values/strings.xml
@@ -50,10 +50,18 @@
<string name="info">Info</string>
+ <string name="camera_permission_rationale">This sample app requires camera access in order to
+ demo the API.</string>
<string name="camera_no_good">No back-facing sufficiently capable camera available!</string>
<string name="camera_disabled">Camera is disabled by device policy</string>
<string name="camera_disconnected">Camera was disconnected before it was opened</string>
<string name="camera_error">Camera service reported an error</string>
<string name="camera_unknown">Unknown camera error: %s</string>
+ <string name="camera_permission_denied_explanation">You\'ve denied a permission that the app
+ needs for core functionality. If you selected &quot;don\'t ask again&quot; in the past then
+ you need to use Settings to re-enable the permission.</string>
+
+ <string name="ok">OK</string>
+ <string name="settings">Settings</string>
</resources>
diff --git a/media/HdrViewfinder/template-params.xml b/media/HdrViewfinder/template-params.xml
index 915e09f3..183aad8e 100644
--- a/media/HdrViewfinder/template-params.xml
+++ b/media/HdrViewfinder/template-params.xml
@@ -20,6 +20,8 @@
<package>com.example.android.hdrviewfinder</package>
<minSdk>21</minSdk>
+ <targetSdkVersion>23</targetSdkVersion>
+ <compileSdkVersion>23</compileSdkVersion>
<strings>
<intro>