aboutsummaryrefslogtreecommitdiff
path: root/media
diff options
context:
space:
mode:
authorYuichi Araki <yaraki@google.com>2015-08-27 03:59:03 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-08-27 03:59:03 +0000
commit0623e0051e00dd8cab1d3698fa21b4bccab818c7 (patch)
treeb7eb25895cec34c1ba3b7bb604ab2481f29dff2d /media
parent9086183043d20655d87b014c033a8e07a6c2e334 (diff)
parentcfc6726372144c5b335a4aae0254cd7a432fec7c (diff)
downloadandroid-0623e0051e00dd8cab1d3698fa21b4bccab818c7.tar.gz
Merge "Camera2Basic: Runtime permission on M" into mnc-devmarshmallow-dev
Diffstat (limited to 'media')
-rw-r--r--media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java173
-rw-r--r--media/Camera2Basic/Application/src/main/res/values/strings.xml2
-rw-r--r--media/Camera2Basic/README.md2
-rw-r--r--media/Camera2Basic/template-params.xml3
4 files changed, 131 insertions, 49 deletions
diff --git a/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java b/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
index 020ca14d..4bf85343 100644
--- a/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
+++ b/media/Camera2Basic/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java
@@ -16,6 +16,7 @@
package com.example.android.camera2basic;
+import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -23,6 +24,7 @@ import android.app.DialogFragment;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
@@ -43,7 +45,8 @@ import android.media.ImageReader;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.Message;
+import android.support.annotation.NonNull;
+import android.support.v13.app.FragmentCompat;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
@@ -66,12 +69,15 @@ import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-public class Camera2BasicFragment extends Fragment implements View.OnClickListener {
+public class Camera2BasicFragment extends Fragment
+ implements View.OnClickListener, FragmentCompat.OnRequestPermissionsResultCallback {
/**
* Conversion from screen rotation to JPEG orientation.
*/
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
+ private static final int REQUEST_CAMERA_PERMISSION = 1;
+ private static final String FRAGMENT_DIALOG = "dialog";
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
@@ -94,14 +100,17 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
* Camera state: Waiting for the focus to be locked.
*/
private static final int STATE_WAITING_LOCK = 1;
+
/**
* Camera state: Waiting for the exposure to be precapture state.
*/
private static final int STATE_WAITING_PRECAPTURE = 2;
+
/**
* Camera state: Waiting for the exposure state to be something other than precapture.
*/
private static final int STATE_WAITING_NON_PRECAPTURE = 3;
+
/**
* Camera state: Picture was taken.
*/
@@ -148,17 +157,16 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
/**
* A {@link CameraCaptureSession } for camera preview.
*/
-
private CameraCaptureSession mCaptureSession;
+
/**
* A reference to the opened {@link CameraDevice}.
*/
-
private CameraDevice mCameraDevice;
+
/**
* The {@link android.util.Size} of camera preview.
*/
-
private Size mPreviewSize;
/**
@@ -167,7 +175,7 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
- public void onOpened(CameraDevice cameraDevice) {
+ public void onOpened(@NonNull CameraDevice cameraDevice) {
// This method is called when the camera is opened. We start camera preview here.
mCameraOpenCloseLock.release();
mCameraDevice = cameraDevice;
@@ -175,14 +183,14 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
}
@Override
- public void onDisconnected(CameraDevice cameraDevice) {
+ public void onDisconnected(@NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}
@Override
- public void onError(CameraDevice cameraDevice, int error) {
+ public void onError(@NonNull CameraDevice cameraDevice, int error) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
@@ -303,43 +311,36 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
}
@Override
- public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
- CaptureResult partialResult) {
+ public void onCaptureProgressed(@NonNull CameraCaptureSession session,
+ @NonNull CaptureRequest request,
+ @NonNull CaptureResult partialResult) {
process(partialResult);
}
@Override
- public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
- TotalCaptureResult result) {
+ public void onCaptureCompleted(@NonNull CameraCaptureSession session,
+ @NonNull CaptureRequest request,
+ @NonNull TotalCaptureResult result) {
process(result);
}
};
/**
- * A {@link Handler} for showing {@link Toast}s.
- */
- private Handler mMessageHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- Activity activity = getActivity();
- if (activity != null) {
- Toast.makeText(activity, (String) msg.obj, Toast.LENGTH_SHORT).show();
- }
- }
- };
-
- /**
* Shows a {@link Toast} on the UI thread.
*
* @param text The message to show
*/
- private void showToast(String text) {
- // We show a Toast by sending request message to mMessageHandler. This makes sure that the
- // Toast is shown on the UI thread.
- Message message = Message.obtain();
- message.obj = text;
- mMessageHandler.sendMessage(message);
+ private void showToast(final String text) {
+ final Activity activity = getActivity();
+ if (activity != null) {
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
}
/**
@@ -355,7 +356,7 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
*/
private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
// Collect the supported resolutions that are at least as big as the preview Surface
- List<Size> bigEnough = new ArrayList<Size>();
+ List<Size> bigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
@@ -375,9 +376,7 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
}
public static Camera2BasicFragment newInstance() {
- Camera2BasicFragment fragment = new Camera2BasicFragment();
- fragment.setRetainInstance(true);
- return fragment;
+ return new Camera2BasicFragment();
}
@Override
@@ -422,6 +421,28 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
super.onPause();
}
+ private void requestCameraPermission() {
+ if (FragmentCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
+ new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);
+ } else {
+ FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
+ REQUEST_CAMERA_PERMISSION);
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ if (requestCode == REQUEST_CAMERA_PERMISSION) {
+ if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
+ ErrorDialog.newInstance(getString(R.string.request_permission))
+ .show(getChildFragmentManager(), FRAGMENT_DIALOG);
+ }
+ } else {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+ }
+
/**
* Sets up member variables related to camera.
*
@@ -437,13 +458,16 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
= manager.getCameraCharacteristics(cameraId);
// We don't use a front facing camera in this sample.
- if (characteristics.get(CameraCharacteristics.LENS_FACING)
- == CameraCharacteristics.LENS_FACING_FRONT) {
+ Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
+ if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
StreamConfigurationMap map = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ if (map == null) {
+ continue;
+ }
// For still image captures, we use the largest available size.
Size largest = Collections.max(
@@ -478,7 +502,8 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
} catch (NullPointerException e) {
// Currently an NPE is thrown when the Camera2API is used but not supported on the
// device this code runs.
- new ErrorDialog().show(getFragmentManager(), "dialog");
+ ErrorDialog.newInstance(getString(R.string.camera_error))
+ .show(getChildFragmentManager(), FRAGMENT_DIALOG);
}
}
@@ -486,6 +511,11 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
* Opens the camera specified by {@link Camera2BasicFragment#mCameraId}.
*/
private void openCamera(int width, int height) {
+ if (getActivity().checkSelfPermission(Manifest.permission.CAMERA)
+ != PackageManager.PERMISSION_GRANTED) {
+ requestCameraPermission();
+ return;
+ }
setUpCameraOutputs(width, height);
configureTransform(width, height);
Activity activity = getActivity();
@@ -574,7 +604,7 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
new CameraCaptureSession.StateCallback() {
@Override
- public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (null == mCameraDevice) {
return;
@@ -600,7 +630,8 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
}
@Override
- public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ public void onConfigureFailed(
+ @NonNull CameraCaptureSession cameraCaptureSession) {
showToast("Failed");
}
}, null
@@ -668,8 +699,8 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
}
/**
- * Run the precapture sequence for capturing a still image. This method should be called when we
- * get a response in {@link #mCaptureCallback} from {@link #lockFocus()}.
+ * Run the precapture sequence for capturing a still image. This method should be called when
+ * we get a response in {@link #mCaptureCallback} from {@link #lockFocus()}.
*/
private void runPrecaptureSequence() {
try {
@@ -714,9 +745,11 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
= new CameraCaptureSession.CaptureCallback() {
@Override
- public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
- TotalCaptureResult result) {
+ public void onCaptureCompleted(@NonNull CameraCaptureSession session,
+ @NonNull CaptureRequest request,
+ @NonNull TotalCaptureResult result) {
showToast("Saved: " + mFile);
+ Log.d(TAG, mFile.toString());
unlockFocus();
}
};
@@ -729,11 +762,12 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
}
/**
- * Unlock the focus. This method should be called when still image capture sequence is finished.
+ * Unlock the focus. This method should be called when still image capture sequence is
+ * finished.
*/
private void unlockFocus() {
try {
- // Reset the autofucos trigger
+ // Reset the auto-focus trigger
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
@@ -827,13 +861,26 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
}
+ /**
+ * Shows an error message dialog.
+ */
public static class ErrorDialog extends DialogFragment {
+ private static final String ARG_MESSAGE = "message";
+
+ public static ErrorDialog newInstance(String message) {
+ ErrorDialog dialog = new ErrorDialog();
+ Bundle args = new Bundle();
+ args.putString(ARG_MESSAGE, message);
+ dialog.setArguments(args);
+ return dialog;
+ }
+
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity();
return new AlertDialog.Builder(activity)
- .setMessage("This device doesn't support Camera2 API.")
+ .setMessage(getArguments().getString(ARG_MESSAGE))
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
@@ -845,4 +892,36 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
}
+ /**
+ * Shows OK/Cancel confirmation dialog about camera permission.
+ */
+ public static class ConfirmationDialog extends DialogFragment {
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Fragment parent = getParentFragment();
+ return new AlertDialog.Builder(getActivity())
+ .setMessage(R.string.request_permission)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ FragmentCompat.requestPermissions(parent,
+ new String[]{Manifest.permission.CAMERA},
+ REQUEST_CAMERA_PERMISSION);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Activity activity = parent.getActivity();
+ if (activity != null) {
+ activity.finish();
+ }
+ }
+ })
+ .create();
+ }
+ }
+
}
diff --git a/media/Camera2Basic/Application/src/main/res/values/strings.xml b/media/Camera2Basic/Application/src/main/res/values/strings.xml
index 66f10008..7fdf6e60 100644
--- a/media/Camera2Basic/Application/src/main/res/values/strings.xml
+++ b/media/Camera2Basic/Application/src/main/res/values/strings.xml
@@ -16,4 +16,6 @@
<resources>
<string name="picture">Picture</string>
<string name="description_info">Info</string>
+ <string name="request_permission">This sample needs camera permission.</string>
+ <string name="camera_error">This device doesn\'t support Camera2 API.</string>
</resources>
diff --git a/media/Camera2Basic/README.md b/media/Camera2Basic/README.md
index 73ad24ae..a77df09d 100644
--- a/media/Camera2Basic/README.md
+++ b/media/Camera2Basic/README.md
@@ -42,7 +42,7 @@ when you are done.
Pre-requisites
--------------
-- Android SDK v21
+- Android SDK v23
- Android Build Tools v23.0.0
- Android Support Repository
diff --git a/media/Camera2Basic/template-params.xml b/media/Camera2Basic/template-params.xml
index 98418305..7f7edef7 100644
--- a/media/Camera2Basic/template-params.xml
+++ b/media/Camera2Basic/template-params.xml
@@ -21,8 +21,9 @@
<name>Camera2Basic</name>
<group>Media</group>
<package>com.example.android.camera2basic</package>
+
+ <dependency>com.android.support:appcompat-v7:23.0.0</dependency>
<minSdk>21</minSdk>
- <targetSdkVersion>22</targetSdkVersion>
<strings>
<intro>
<![CDATA[