diff --git a/Application/build.gradle b/Application/build.gradle
index 7292999fb0d53b9818b653ef474ea28d0d21e2f0..77d3fd41c233c448bf522243182d385536c9c4a8 100644
--- a/Application/build.gradle
+++ b/Application/build.gradle
@@ -19,6 +19,7 @@ dependencies {
compile "com.android.support:support-v4:23.0.0"
compile "com.android.support:support-v13:23.0.0"
compile "com.android.support:cardview-v7:23.0.0"
+ compile 'com.android.support:appcompat-v7:23.0.0'
}
// The sample build uses multiple directories to
@@ -35,7 +36,7 @@ android {
defaultConfig {
minSdkVersion 21
- targetSdkVersion 22
+ targetSdkVersion 23
}
compileOptions {
diff --git a/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.java b/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.java
index 78e276a97d6ca8a70cbed0da50e8656777c85a3b..1ea53187f55062693e80651a00f90722a42931e6 100644
--- a/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.java
+++ b/Application/src/main/java/com/example/android/camera2video/Camera2VideoFragment.java
@@ -16,6 +16,7 @@
package com.example.android.camera2video;
+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.Matrix;
import android.graphics.RectF;
@@ -39,6 +41,9 @@ import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
+import android.support.annotation.NonNull;
+import android.support.v13.app.FragmentCompat;
+import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
@@ -59,11 +64,19 @@ import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
-public class Camera2VideoFragment extends Fragment implements View.OnClickListener {
+public class Camera2VideoFragment extends Fragment
+ implements View.OnClickListener, FragmentCompat.OnRequestPermissionsResultCallback {
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private static final String TAG = "Camera2VideoFragment";
+ private static final int REQUEST_VIDEO_PERMISSIONS = 1;
+ private static final String FRAGMENT_DIALOG = "dialog";
+
+ private static final String[] VIDEO_PERMISSIONS = {
+ Manifest.permission.CAMERA,
+ Manifest.permission.RECORD_AUDIO,
+ };
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
@@ -88,7 +101,8 @@ public class Camera2VideoFragment extends Fragment implements View.OnClickListen
private CameraDevice mCameraDevice;
/**
- * A reference to the current {@link android.hardware.camera2.CameraCaptureSession} for preview.
+ * A reference to the current {@link android.hardware.camera2.CameraCaptureSession} for
+ * preview.
*/
private CameraCaptureSession mPreviewSession;
@@ -198,14 +212,12 @@ public class Camera2VideoFragment extends Fragment implements View.OnClickListen
};
public static Camera2VideoFragment newInstance() {
- Camera2VideoFragment fragment = new Camera2VideoFragment();
- fragment.setRetainInstance(true);
- return fragment;
+ return new Camera2VideoFragment();
}
/**
- * In this sample, we choose a video size with 3x4 aspect ratio. Also, we don't use sizes larger
- * than 1080p, since MediaRecorder cannot handle such a high-resolution video.
+ * In this sample, we choose a video size with 3x4 aspect ratio. Also, we don't use sizes
+ * larger than 1080p, since MediaRecorder cannot handle such a high-resolution video.
*
* @param choices The list of available sizes
* @return The video size
@@ -331,16 +343,79 @@ public class Camera2VideoFragment extends Fragment implements View.OnClickListen
}
}
+ /**
+ * Gets whether you should show UI with rationale for requesting permissions.
+ *
+ * @param permissions The permissions your app wants to request.
+ * @return Whether you can show permission rationale UI.
+ */
+ private boolean shouldShowRequestPermissionRationale(String[] permissions) {
+ for (String permission : permissions) {
+ if (FragmentCompat.shouldShowRequestPermissionRationale(this, permission)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Requests permissions needed for recording video.
+ */
+ private void requestVideoPermissions() {
+ if (shouldShowRequestPermissionRationale(VIDEO_PERMISSIONS)) {
+ new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);
+ } else {
+ FragmentCompat.requestPermissions(this, VIDEO_PERMISSIONS, REQUEST_VIDEO_PERMISSIONS);
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ Log.d(TAG, "onRequestPermissionsResult");
+ if (requestCode == REQUEST_VIDEO_PERMISSIONS) {
+ if (grantResults.length == VIDEO_PERMISSIONS.length) {
+ for (int result : grantResults) {
+ if (result != PackageManager.PERMISSION_GRANTED) {
+ ErrorDialog.newInstance(getString(R.string.permission_request))
+ .show(getChildFragmentManager(), FRAGMENT_DIALOG);
+ break;
+ }
+ }
+ } else {
+ ErrorDialog.newInstance(getString(R.string.permission_request))
+ .show(getChildFragmentManager(), FRAGMENT_DIALOG);
+ }
+ } else {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+ }
+
+ private boolean hasPermissionsGranted(String[] permissions) {
+ for (String permission : permissions) {
+ if (ActivityCompat.checkSelfPermission(getActivity(), permission)
+ != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Tries to open a {@link CameraDevice}. The result is listened by `mStateCallback`.
*/
private void openCamera(int width, int height) {
+ if (!hasPermissionsGranted(VIDEO_PERMISSIONS)) {
+ requestVideoPermissions();
+ return;
+ }
final Activity activity = getActivity();
if (null == activity || activity.isFinishing()) {
return;
}
CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
+ Log.d(TAG, "tryAcquire");
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
@@ -369,7 +444,8 @@ public class Camera2VideoFragment 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);
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.");
}
@@ -389,7 +465,7 @@ public class Camera2VideoFragment extends Fragment implements View.OnClickListen
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.");
} finally {
- mCameraOpenCloseLock.release();
+ mCameraOpenCloseLock.release();
}
}
@@ -559,11 +635,21 @@ public class Camera2VideoFragment extends Fragment implements View.OnClickListen
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) {
@@ -575,4 +661,30 @@ public class Camera2VideoFragment extends Fragment implements View.OnClickListen
}
+ public static class ConfirmationDialog extends DialogFragment {
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Fragment parent = getParentFragment();
+ return new AlertDialog.Builder(getActivity())
+ .setMessage(R.string.permission_request)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ FragmentCompat.requestPermissions(parent, VIDEO_PERMISSIONS,
+ REQUEST_VIDEO_PERMISSIONS);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ parent.getActivity().finish();
+ }
+ })
+ .create();
+ }
+
+ }
+
}
diff --git a/Application/src/main/res/values/strings.xml b/Application/src/main/res/values/strings.xml
index bf5e439da4d938364c97e4a0fe526300a7be4690..bce323f1a79a65efe64c26daec3950b310d0b3bb 100644
--- a/Application/src/main/res/values/strings.xml
+++ b/Application/src/main/res/values/strings.xml
@@ -3,4 +3,6 @@
Record
Stop
Info
+ This sample needs permission for camera and audio recording.
+ This device doesn\'t support Camera2 API.
\ No newline at end of file