Skip to content

Commit 241c6fa

Browse files
Auto-update
1 parent 5795fc9 commit 241c6fa

File tree

3 files changed

+130
-48
lines changed

3 files changed

+130
-48
lines changed

Application/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dependencies {
1919
compile "com.android.support:support-v4:23.0.0"
2020
compile "com.android.support:support-v13:23.0.0"
2121
compile "com.android.support:cardview-v7:23.0.0"
22+
compile 'com.android.support:appcompat-v7:23.0.0'
2223
}
2324

2425
// The sample build uses multiple directories to
@@ -35,7 +36,7 @@ android {
3536

3637
defaultConfig {
3738
minSdkVersion 21
38-
targetSdkVersion 22
39+
targetSdkVersion 23
3940
}
4041

4142
compileOptions {

Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java

Lines changed: 126 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616

1717
package com.example.android.camera2basic;
1818

19+
import android.Manifest;
1920
import android.app.Activity;
2021
import android.app.AlertDialog;
2122
import android.app.Dialog;
2223
import android.app.DialogFragment;
2324
import android.app.Fragment;
2425
import android.content.Context;
2526
import android.content.DialogInterface;
27+
import android.content.pm.PackageManager;
2628
import android.content.res.Configuration;
2729
import android.graphics.ImageFormat;
2830
import android.graphics.Matrix;
@@ -43,7 +45,8 @@
4345
import android.os.Bundle;
4446
import android.os.Handler;
4547
import android.os.HandlerThread;
46-
import android.os.Message;
48+
import android.support.annotation.NonNull;
49+
import android.support.v13.app.FragmentCompat;
4750
import android.util.Log;
4851
import android.util.Size;
4952
import android.util.SparseIntArray;
@@ -66,12 +69,15 @@
6669
import java.util.concurrent.Semaphore;
6770
import java.util.concurrent.TimeUnit;
6871

69-
public class Camera2BasicFragment extends Fragment implements View.OnClickListener {
72+
public class Camera2BasicFragment extends Fragment
73+
implements View.OnClickListener, FragmentCompat.OnRequestPermissionsResultCallback {
7074

7175
/**
7276
* Conversion from screen rotation to JPEG orientation.
7377
*/
7478
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
79+
private static final int REQUEST_CAMERA_PERMISSION = 1;
80+
private static final String FRAGMENT_DIALOG = "dialog";
7581

7682
static {
7783
ORIENTATIONS.append(Surface.ROTATION_0, 90);
@@ -94,14 +100,17 @@ public class Camera2BasicFragment extends Fragment implements View.OnClickListen
94100
* Camera state: Waiting for the focus to be locked.
95101
*/
96102
private static final int STATE_WAITING_LOCK = 1;
103+
97104
/**
98105
* Camera state: Waiting for the exposure to be precapture state.
99106
*/
100107
private static final int STATE_WAITING_PRECAPTURE = 2;
108+
101109
/**
102110
* Camera state: Waiting for the exposure state to be something other than precapture.
103111
*/
104112
private static final int STATE_WAITING_NON_PRECAPTURE = 3;
113+
105114
/**
106115
* Camera state: Picture was taken.
107116
*/
@@ -148,17 +157,16 @@ public void onSurfaceTextureUpdated(SurfaceTexture texture) {
148157
/**
149158
* A {@link CameraCaptureSession } for camera preview.
150159
*/
151-
152160
private CameraCaptureSession mCaptureSession;
161+
153162
/**
154163
* A reference to the opened {@link CameraDevice}.
155164
*/
156-
157165
private CameraDevice mCameraDevice;
166+
158167
/**
159168
* The {@link android.util.Size} of camera preview.
160169
*/
161-
162170
private Size mPreviewSize;
163171

164172
/**
@@ -167,22 +175,22 @@ public void onSurfaceTextureUpdated(SurfaceTexture texture) {
167175
private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
168176

169177
@Override
170-
public void onOpened(CameraDevice cameraDevice) {
178+
public void onOpened(@NonNull CameraDevice cameraDevice) {
171179
// This method is called when the camera is opened. We start camera preview here.
172180
mCameraOpenCloseLock.release();
173181
mCameraDevice = cameraDevice;
174182
createCameraPreviewSession();
175183
}
176184

177185
@Override
178-
public void onDisconnected(CameraDevice cameraDevice) {
186+
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
179187
mCameraOpenCloseLock.release();
180188
cameraDevice.close();
181189
mCameraDevice = null;
182190
}
183191

184192
@Override
185-
public void onError(CameraDevice cameraDevice, int error) {
193+
public void onError(@NonNull CameraDevice cameraDevice, int error) {
186194
mCameraOpenCloseLock.release();
187195
cameraDevice.close();
188196
mCameraDevice = null;
@@ -303,43 +311,36 @@ private void process(CaptureResult result) {
303311
}
304312

305313
@Override
306-
public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
307-
CaptureResult partialResult) {
314+
public void onCaptureProgressed(@NonNull CameraCaptureSession session,
315+
@NonNull CaptureRequest request,
316+
@NonNull CaptureResult partialResult) {
308317
process(partialResult);
309318
}
310319

311320
@Override
312-
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
313-
TotalCaptureResult result) {
321+
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
322+
@NonNull CaptureRequest request,
323+
@NonNull TotalCaptureResult result) {
314324
process(result);
315325
}
316326

317327
};
318328

319-
/**
320-
* A {@link Handler} for showing {@link Toast}s.
321-
*/
322-
private Handler mMessageHandler = new Handler() {
323-
@Override
324-
public void handleMessage(Message msg) {
325-
Activity activity = getActivity();
326-
if (activity != null) {
327-
Toast.makeText(activity, (String) msg.obj, Toast.LENGTH_SHORT).show();
328-
}
329-
}
330-
};
331-
332329
/**
333330
* Shows a {@link Toast} on the UI thread.
334331
*
335332
* @param text The message to show
336333
*/
337-
private void showToast(String text) {
338-
// We show a Toast by sending request message to mMessageHandler. This makes sure that the
339-
// Toast is shown on the UI thread.
340-
Message message = Message.obtain();
341-
message.obj = text;
342-
mMessageHandler.sendMessage(message);
334+
private void showToast(final String text) {
335+
final Activity activity = getActivity();
336+
if (activity != null) {
337+
activity.runOnUiThread(new Runnable() {
338+
@Override
339+
public void run() {
340+
Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
341+
}
342+
});
343+
}
343344
}
344345

345346
/**
@@ -355,7 +356,7 @@ private void showToast(String text) {
355356
*/
356357
private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
357358
// Collect the supported resolutions that are at least as big as the preview Surface
358-
List<Size> bigEnough = new ArrayList<Size>();
359+
List<Size> bigEnough = new ArrayList<>();
359360
int w = aspectRatio.getWidth();
360361
int h = aspectRatio.getHeight();
361362
for (Size option : choices) {
@@ -375,9 +376,7 @@ private static Size chooseOptimalSize(Size[] choices, int width, int height, Siz
375376
}
376377

377378
public static Camera2BasicFragment newInstance() {
378-
Camera2BasicFragment fragment = new Camera2BasicFragment();
379-
fragment.setRetainInstance(true);
380-
return fragment;
379+
return new Camera2BasicFragment();
381380
}
382381

383382
@Override
@@ -422,6 +421,28 @@ public void onPause() {
422421
super.onPause();
423422
}
424423

424+
private void requestCameraPermission() {
425+
if (FragmentCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
426+
new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);
427+
} else {
428+
FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
429+
REQUEST_CAMERA_PERMISSION);
430+
}
431+
}
432+
433+
@Override
434+
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
435+
@NonNull int[] grantResults) {
436+
if (requestCode == REQUEST_CAMERA_PERMISSION) {
437+
if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
438+
ErrorDialog.newInstance(getString(R.string.request_permission))
439+
.show(getChildFragmentManager(), FRAGMENT_DIALOG);
440+
}
441+
} else {
442+
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
443+
}
444+
}
445+
425446
/**
426447
* Sets up member variables related to camera.
427448
*
@@ -437,13 +458,16 @@ private void setUpCameraOutputs(int width, int height) {
437458
= manager.getCameraCharacteristics(cameraId);
438459

439460
// We don't use a front facing camera in this sample.
440-
if (characteristics.get(CameraCharacteristics.LENS_FACING)
441-
== CameraCharacteristics.LENS_FACING_FRONT) {
461+
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
462+
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
442463
continue;
443464
}
444465

445466
StreamConfigurationMap map = characteristics.get(
446467
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
468+
if (map == null) {
469+
continue;
470+
}
447471

448472
// For still image captures, we use the largest available size.
449473
Size largest = Collections.max(
@@ -478,14 +502,20 @@ private void setUpCameraOutputs(int width, int height) {
478502
} catch (NullPointerException e) {
479503
// Currently an NPE is thrown when the Camera2API is used but not supported on the
480504
// device this code runs.
481-
new ErrorDialog().show(getFragmentManager(), "dialog");
505+
ErrorDialog.newInstance(getString(R.string.camera_error))
506+
.show(getChildFragmentManager(), FRAGMENT_DIALOG);
482507
}
483508
}
484509

485510
/**
486511
* Opens the camera specified by {@link Camera2BasicFragment#mCameraId}.
487512
*/
488513
private void openCamera(int width, int height) {
514+
if (getActivity().checkSelfPermission(Manifest.permission.CAMERA)
515+
!= PackageManager.PERMISSION_GRANTED) {
516+
requestCameraPermission();
517+
return;
518+
}
489519
setUpCameraOutputs(width, height);
490520
configureTransform(width, height);
491521
Activity activity = getActivity();
@@ -574,7 +604,7 @@ private void createCameraPreviewSession() {
574604
new CameraCaptureSession.StateCallback() {
575605

576606
@Override
577-
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
607+
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
578608
// The camera is already closed
579609
if (null == mCameraDevice) {
580610
return;
@@ -600,7 +630,8 @@ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
600630
}
601631

602632
@Override
603-
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
633+
public void onConfigureFailed(
634+
@NonNull CameraCaptureSession cameraCaptureSession) {
604635
showToast("Failed");
605636
}
606637
}, null
@@ -668,8 +699,8 @@ private void lockFocus() {
668699
}
669700

670701
/**
671-
* Run the precapture sequence for capturing a still image. This method should be called when we
672-
* get a response in {@link #mCaptureCallback} from {@link #lockFocus()}.
702+
* Run the precapture sequence for capturing a still image. This method should be called when
703+
* we get a response in {@link #mCaptureCallback} from {@link #lockFocus()}.
673704
*/
674705
private void runPrecaptureSequence() {
675706
try {
@@ -714,9 +745,11 @@ private void captureStillPicture() {
714745
= new CameraCaptureSession.CaptureCallback() {
715746

716747
@Override
717-
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
718-
TotalCaptureResult result) {
748+
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
749+
@NonNull CaptureRequest request,
750+
@NonNull TotalCaptureResult result) {
719751
showToast("Saved: " + mFile);
752+
Log.d(TAG, mFile.toString());
720753
unlockFocus();
721754
}
722755
};
@@ -729,11 +762,12 @@ public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest requ
729762
}
730763

731764
/**
732-
* Unlock the focus. This method should be called when still image capture sequence is finished.
765+
* Unlock the focus. This method should be called when still image capture sequence is
766+
* finished.
733767
*/
734768
private void unlockFocus() {
735769
try {
736-
// Reset the autofucos trigger
770+
// Reset the auto-focus trigger
737771
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
738772
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
739773
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
@@ -827,13 +861,26 @@ public int compare(Size lhs, Size rhs) {
827861

828862
}
829863

864+
/**
865+
* Shows an error message dialog.
866+
*/
830867
public static class ErrorDialog extends DialogFragment {
831868

869+
private static final String ARG_MESSAGE = "message";
870+
871+
public static ErrorDialog newInstance(String message) {
872+
ErrorDialog dialog = new ErrorDialog();
873+
Bundle args = new Bundle();
874+
args.putString(ARG_MESSAGE, message);
875+
dialog.setArguments(args);
876+
return dialog;
877+
}
878+
832879
@Override
833880
public Dialog onCreateDialog(Bundle savedInstanceState) {
834881
final Activity activity = getActivity();
835882
return new AlertDialog.Builder(activity)
836-
.setMessage("This device doesn't support Camera2 API.")
883+
.setMessage(getArguments().getString(ARG_MESSAGE))
837884
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
838885
@Override
839886
public void onClick(DialogInterface dialogInterface, int i) {
@@ -845,4 +892,36 @@ public void onClick(DialogInterface dialogInterface, int i) {
845892

846893
}
847894

895+
/**
896+
* Shows OK/Cancel confirmation dialog about camera permission.
897+
*/
898+
public static class ConfirmationDialog extends DialogFragment {
899+
900+
@Override
901+
public Dialog onCreateDialog(Bundle savedInstanceState) {
902+
final Fragment parent = getParentFragment();
903+
return new AlertDialog.Builder(getActivity())
904+
.setMessage(R.string.request_permission)
905+
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
906+
@Override
907+
public void onClick(DialogInterface dialog, int which) {
908+
FragmentCompat.requestPermissions(parent,
909+
new String[]{Manifest.permission.CAMERA},
910+
REQUEST_CAMERA_PERMISSION);
911+
}
912+
})
913+
.setNegativeButton(android.R.string.cancel,
914+
new DialogInterface.OnClickListener() {
915+
@Override
916+
public void onClick(DialogInterface dialog, int which) {
917+
Activity activity = parent.getActivity();
918+
if (activity != null) {
919+
activity.finish();
920+
}
921+
}
922+
})
923+
.create();
924+
}
925+
}
926+
848927
}

0 commit comments

Comments
 (0)