From 2441fe067d2f20cf71fbff7e6fdd7e182902c954 Mon Sep 17 00:00:00 2001 From: Jerry Chen Date: Thu, 11 Jul 2019 19:25:02 -0400 Subject: [PATCH] v0.0.2; better notification; better control of AE/AF; --- app/src/main/AndroidManifest.xml | 2 +- .../java/jerryc05/unlockme/MainActivity.java | 29 ++-- .../unlockme/helpers/Camera2APIHelper.java | 127 +++++++++++++++--- .../unlockme/helpers/DeviceAdminHelper.java | 4 +- ...ceiver.java => MyDeviceAdminReceiver.java} | 15 ++- 5 files changed, 139 insertions(+), 38 deletions(-) rename app/src/main/java/jerryc05/unlockme/receivers/{MyDAReceiver.java => MyDeviceAdminReceiver.java} (57%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9a61ed9..37d9f44 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -35,7 +35,7 @@ weakMainActivity; public static ThreadPoolExecutor threadPoolExecutor; @Override @@ -40,6 +42,7 @@ protected void onCreate(Bundle savedInstanceState) { @Override public void run() { applicationContext = getApplicationContext(); + weakMainActivity=new WeakReference<>(MainActivity.this); findViewById(R.id.activity_main_button_front) .setOnClickListener(MainActivity.this); findViewById(R.id.activity_main_button_back) @@ -49,19 +52,19 @@ public void run() { }); } -// @Override -// protected void onStart() { -// super.onStart(); -// -// threadPoolExecutor.execute(new Runnable() { -// @Override -// public void run() { -// if (requestDeviceAdminLock != null) -// requestDeviceAdminLock.lock(); -// DeviceAdminHelper.requestPermission(MainActivity.this); -// } -// }); -// } + @Override + protected void onStart() { + super.onStart(); + + threadPoolExecutor.execute(new Runnable() { + @Override + public void run() { + if (requestDeviceAdminLock != null) + requestDeviceAdminLock.lock(); + DeviceAdminHelper.requestPermission(MainActivity.this); + } + }); + } @Override diff --git a/app/src/main/java/jerryc05/unlockme/helpers/Camera2APIHelper.java b/app/src/main/java/jerryc05/unlockme/helpers/Camera2APIHelper.java index a6aa6e8..a11deb7 100644 --- a/app/src/main/java/jerryc05/unlockme/helpers/Camera2APIHelper.java +++ b/app/src/main/java/jerryc05/unlockme/helpers/Camera2APIHelper.java @@ -9,6 +9,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.pm.PackageManager; +import android.graphics.BitmapFactory; import android.graphics.ImageFormat; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; @@ -60,6 +61,7 @@ public final class Camera2APIHelper { protected static CameraDevice.StateCallback openCameraStateCallback; private static SparseIntArray orientationsMap; protected static DialogInterface.OnClickListener requestPermissionRationaleOnClickListener; + private static ImageReader previewImageReader; private static ImageReader mImageReader; private static CameraCaptureSession.CaptureCallback mCaptureCallback; private static ImageReader.OnImageAvailableListener onImageAvailableListener; @@ -237,7 +239,15 @@ protected static void captureStillImage(final MainActivity activity) { } } - private static ImageReader getImageReader() { + protected static ImageReader getPreviewImageReader() { + if (previewImageReader == null) { + previewImageReader = ImageReader.newInstance(1, 1, + ImageFormat.JPEG, 1); + } + return previewImageReader; + } + + protected static ImageReader getImageReader() { if (mImageReader == null) { final StreamConfigurationMap streamConfigurationMap = mCameraCharacteristics.get( @@ -248,12 +258,14 @@ private static ImageReader getImageReader() { new Comparator() { @Override public int compare(Size prev, Size next) { - return prev.getWidth() - next.getWidth(); + int width = prev.getWidth() - next.getWidth(); + return width != 0 ? width : + prev.getHeight() - next.getHeight(); } }); mImageReader = ImageReader.newInstance( mCaptureSize.getWidth(), mCaptureSize.getHeight(), - ImageFormat.JPEG, 2); + ImageFormat.JPEG, 1); mImageReader.setOnImageAvailableListener( getOnImageAvailableListener(), null); } @@ -270,11 +282,6 @@ public void onConfigured(CameraCaptureSession cameraCaptureSession) { Log.d(TAG, "mCaptureStillImageStateCallback#onConfigured: "); try { mCameraCaptureSession = cameraCaptureSession; -// cameraCaptureSession.setRepeatingRequest( -// getPreviewCaptureRequest(activity), null, null); - - cameraCaptureSession.abortCaptures(); - cameraCaptureSession.stopRepeating(); cameraCaptureSession.capture(getStillImageCaptureRequest(activity), getCaptureCallback(), null); @@ -292,7 +299,8 @@ public void onConfigureFailed(CameraCaptureSession session) { return mStateCallback; } - protected static CaptureRequest getPreviewCaptureRequest(final MainActivity activity) + protected static CaptureRequest getPreviewCaptureRequest( + final MainActivity activity) throws CameraAccessException { CaptureRequest.Builder mCaptureRequestBuilder = mCameraDevice .createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); @@ -303,23 +311,34 @@ protected static CaptureRequest getPreviewCaptureRequest(final MainActivity acti return mCaptureRequestBuilder.build(); } - protected static CaptureRequest getStillImageCaptureRequest(final MainActivity activity) + protected static CaptureRequest getStillImageCaptureRequest( + final MainActivity activity) throws CameraAccessException { CaptureRequest.Builder mCaptureRequestBuilder = mCameraDevice .createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); - mCaptureRequestBuilder.set(CaptureRequest.CONTROL_MODE, - CameraMetadata.CONTROL_MODE_AUTO); + mCaptureRequestBuilder.set( + CaptureRequest.CONTROL_AE_MODE, + CaptureRequest.CONTROL_AE_MODE_ON + ); + mCaptureRequestBuilder.set( + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START + ); + mCaptureRequestBuilder.set( + CaptureRequest.CONTROL_AF_MODE, + CameraMetadata.CONTROL_AF_MODE_AUTO + ); + mCaptureRequestBuilder.set( + CaptureRequest.CONTROL_AF_TRIGGER, + CaptureRequest.CONTROL_AF_TRIGGER_START + ); mCaptureRequestBuilder.addTarget(getImageReader().getSurface()); - final int currentRotation = activity.getWindowManager() - .getDefaultDisplay().getRotation(); - if (BuildConfig.DEBUG) - Log.d(TAG, "getStillImageCaptureRequest: Orientation: " + - currentRotation); - mCaptureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, (predefinedFacing == CameraCharacteristics.LENS_FACING_FRONT ? getFrontOrientationsMap() - : getBackOrientationsMap()).get(currentRotation)); + : getBackOrientationsMap()).get( + activity.getWindowManager().getDefaultDisplay().getRotation())); + return mCaptureRequestBuilder.build(); } @@ -371,9 +390,37 @@ public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); + if (BuildConfig.DEBUG) Log.d(TAG, "mCaptureCallback#onCaptureCompleted: "); + final CaptureRequest.Builder mCaptureRequestBuilder; + try { + mCaptureRequestBuilder = mCameraDevice + .createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); + mCaptureRequestBuilder.set( + CaptureRequest.CONTROL_AE_MODE, + CaptureRequest.CONTROL_AE_MODE_OFF + ); + mCaptureRequestBuilder.set( + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, + CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE + ); + mCaptureRequestBuilder.set( + CaptureRequest.CONTROL_AF_MODE, + CameraMetadata.CONTROL_AF_MODE_OFF + ); + mCaptureRequestBuilder.set( + CaptureRequest.CONTROL_AF_TRIGGER, + CameraMetadata.CONTROL_AF_TRIGGER_CANCEL + ); + mCaptureRequestBuilder.addTarget(getPreviewImageReader().getSurface()); + + session.capture(mCaptureRequestBuilder.build(), + null, null); + } catch (Exception e) { + e.printStackTrace(); + } closeCamera2(); } }; @@ -389,6 +436,8 @@ protected static void saveImageToDisk(final byte[] bytes) { if (BuildConfig.DEBUG) Log.d(TAG, "saveImageToDisk: " + dirName + fileName); + + notifyPictureToUI("Picture Taken", fileName, bytes); final File dir = new File(dirName), file = new File(dir, fileName); @@ -399,7 +448,6 @@ protected static void saveImageToDisk(final byte[] bytes) { try (final FileOutputStream fileOutputStream = new FileOutputStream(file)) { fileOutputStream.write(bytes); - notifyToUI("Picture Taken", fileName, null); } catch (final Exception e) { if (BuildConfig.DEBUG) Log.e(TAG, "saveImageToDisk: ", e); @@ -470,4 +518,43 @@ public static void notifyToUI(final String contentTitle, notificationManager.notify(-1, builder.build()); } + + public static void notifyPictureToUI(final String contentTitle, + final String contentText, + final byte[] bytes) { + final Notification.Builder builder = new Notification.Builder( + MainActivity.applicationContext) + .setContentTitle(contentTitle) + .setContentText(contentText) + .setSmallIcon(R.drawable.ic_launcher_shield_foreground) + .setShowWhen(true) + .setStyle(new Notification.BigPictureStyle() + .bigPicture(BitmapFactory.decodeByteArray( + bytes, 0, bytes.length))); + + NotificationManager notificationManager = (NotificationManager) + MainActivity.applicationContext. + getSystemService(NOTIFICATION_SERVICE); + assert notificationManager != null; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + final String CHANNEL_ID = "Image Captured Report"; + if (notificationManager.getNotificationChannel(CHANNEL_ID) == null) { + NotificationChannel mChannel = new NotificationChannel( + CHANNEL_ID, CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT); + mChannel.setDescription("Image captured report notification channel for UnlockMe"); + mChannel.enableLights(true); + mChannel.enableVibration(false); + mChannel.setShowBadge(true); + mChannel.setImportance(NotificationManager.IMPORTANCE_HIGH); + notificationManager.createNotificationChannel(mChannel); + } + builder + .setChannelId(CHANNEL_ID) + .setBadgeIconType(Notification.BADGE_ICON_LARGE); + } else + builder.setPriority(Notification.PRIORITY_HIGH); + + notificationManager.notify(-1, builder.build()); + } } diff --git a/app/src/main/java/jerryc05/unlockme/helpers/DeviceAdminHelper.java b/app/src/main/java/jerryc05/unlockme/helpers/DeviceAdminHelper.java index 32be175..5034ff0 100644 --- a/app/src/main/java/jerryc05/unlockme/helpers/DeviceAdminHelper.java +++ b/app/src/main/java/jerryc05/unlockme/helpers/DeviceAdminHelper.java @@ -14,7 +14,7 @@ import jerryc05.unlockme.BuildConfig; import jerryc05.unlockme.MainActivity; import jerryc05.unlockme.R; -import jerryc05.unlockme.receivers.MyDAReceiver; +import jerryc05.unlockme.receivers.MyDeviceAdminReceiver; public final class DeviceAdminHelper { @@ -36,7 +36,7 @@ public static void requestPermission(MainActivity activity) { activity.getSystemService(Context.DEVICE_POLICY_SERVICE)); if (mComponentName == null) mComponentName = - new ComponentName(activity, MyDAReceiver.class); + new ComponentName(activity, MyDeviceAdminReceiver.class); if (!mDevicePolicyManager.isAdminActive(mComponentName)) { final Intent intentDeviceAdmin = new Intent( diff --git a/app/src/main/java/jerryc05/unlockme/receivers/MyDAReceiver.java b/app/src/main/java/jerryc05/unlockme/receivers/MyDeviceAdminReceiver.java similarity index 57% rename from app/src/main/java/jerryc05/unlockme/receivers/MyDAReceiver.java rename to app/src/main/java/jerryc05/unlockme/receivers/MyDeviceAdminReceiver.java index efc5ccb..e1eb926 100644 --- a/app/src/main/java/jerryc05/unlockme/receivers/MyDAReceiver.java +++ b/app/src/main/java/jerryc05/unlockme/receivers/MyDeviceAdminReceiver.java @@ -3,15 +3,18 @@ import android.app.admin.DeviceAdminReceiver; import android.content.Context; import android.content.Intent; +import android.hardware.camera2.CameraCharacteristics; import android.os.UserHandle; import android.util.Log; import jerryc05.unlockme.BuildConfig; +import jerryc05.unlockme.MainActivity; +import jerryc05.unlockme.helpers.Camera2APIHelper; @SuppressWarnings("NullableProblems") -public class MyDAReceiver extends DeviceAdminReceiver { +public class MyDeviceAdminReceiver extends DeviceAdminReceiver { - private final static String TAG = MyDAReceiver.class.getSimpleName(); + private final static String TAG = MyDeviceAdminReceiver.class.getSimpleName(); private static int failedAttempt; @Override @@ -20,6 +23,14 @@ public void onPasswordFailed(Context context, Intent intent, UserHandle user) { if (BuildConfig.DEBUG) Log.d(TAG, "onPasswordFailed: " + ++failedAttempt); + MainActivity.threadPoolExecutor.execute(new Runnable() { + @Override + public void run() { + Camera2APIHelper.automaticTakePhoto( + MainActivity.weakMainActivity.get(), + CameraCharacteristics.LENS_FACING_FRONT); + } + }); } @Override