From ae86b3fdcbef7cff9821e5d086f8c5364c13368d Mon Sep 17 00:00:00 2001 From: roynatech2544 Date: Tue, 9 Nov 2021 22:19:53 +0900 Subject: [PATCH] universal7885: CameraLightSensor: Merge codes to 2 files and fix bugs * Add proguard rules too * Auto-Brightness still working even if the settings is turned off --- a20/AndroidProducts.mk | 2 - a20/aosp_a20.mk | 8 - .../apps/CameraLightSensor/Android.bp | 3 + .../CameraLightSensor/AndroidManifest.xml | 6 +- .../apps/CameraLightSensor/proguard.flags | 7 + .../cameralightsensor/BootReceiver.java | 3 +- .../cameralightsensor/Camera2Service.java | 328 ------------- .../CameraLightSensorService.java | 452 +++++++++++++++--- universal7885-common/vendor_detect/prebuilt | Bin 50800 -> 0 bytes 9 files changed, 388 insertions(+), 421 deletions(-) delete mode 100644 a20/AndroidProducts.mk delete mode 100644 a20/aosp_a20.mk create mode 100755 universal7885-common/apps/CameraLightSensor/proguard.flags delete mode 100755 universal7885-common/apps/CameraLightSensor/src/com/eurekateam/cameralightsensor/Camera2Service.java delete mode 100755 universal7885-common/vendor_detect/prebuilt diff --git a/a20/AndroidProducts.mk b/a20/AndroidProducts.mk deleted file mode 100644 index 79f5667..0000000 --- a/a20/AndroidProducts.mk +++ /dev/null @@ -1,2 +0,0 @@ -PRODUCT_MAKEFILES := \ - $(LOCAL_DIR)/aosp_a20.mk diff --git a/a20/aosp_a20.mk b/a20/aosp_a20.mk deleted file mode 100644 index 05c2ff2..0000000 --- a/a20/aosp_a20.mk +++ /dev/null @@ -1,8 +0,0 @@ -# Auto-Generated by device/samsung/a20/setup.sh -$(call inherit-product, device/samsung/a20/full_a20.mk) -$(call inherit-product, vendor/aosp/config/common_full_phone.mk) -PRODUCT_NAME := aosp_a20 - -# Additional Props -TARGET_FACE_UNLOCK_SUPPORTED := true -TARGET_BOOT_ANIMATION_RES := 720 diff --git a/universal7885-common/apps/CameraLightSensor/Android.bp b/universal7885-common/apps/CameraLightSensor/Android.bp index 9f4e546..6c8e4e6 100644 --- a/universal7885-common/apps/CameraLightSensor/Android.bp +++ b/universal7885-common/apps/CameraLightSensor/Android.bp @@ -7,4 +7,7 @@ android_app { privileged: true, certificate: "platform", static_libs: [ "androidx.core_core" ], + optimize: { + proguard_flags_files: ["proguard.flags"], + }, } diff --git a/universal7885-common/apps/CameraLightSensor/AndroidManifest.xml b/universal7885-common/apps/CameraLightSensor/AndroidManifest.xml index 0ebe4f4..3053306 100755 --- a/universal7885-common/apps/CameraLightSensor/AndroidManifest.xml +++ b/universal7885-common/apps/CameraLightSensor/AndroidManifest.xml @@ -38,9 +38,5 @@ - - - \ No newline at end of file + diff --git a/universal7885-common/apps/CameraLightSensor/proguard.flags b/universal7885-common/apps/CameraLightSensor/proguard.flags new file mode 100755 index 0000000..25042b4 --- /dev/null +++ b/universal7885-common/apps/CameraLightSensor/proguard.flags @@ -0,0 +1,7 @@ +# Uncomment this to preserve the line number information for +# debugging stack traces. +-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +-renamesourcefileattribute SourceFile diff --git a/universal7885-common/apps/CameraLightSensor/src/com/eurekateam/cameralightsensor/BootReceiver.java b/universal7885-common/apps/CameraLightSensor/src/com/eurekateam/cameralightsensor/BootReceiver.java index 33b33fc..c15b565 100755 --- a/universal7885-common/apps/CameraLightSensor/src/com/eurekateam/cameralightsensor/BootReceiver.java +++ b/universal7885-common/apps/CameraLightSensor/src/com/eurekateam/cameralightsensor/BootReceiver.java @@ -12,8 +12,7 @@ public class BootReceiver extends BroadcastReceiver { final Intent i = new Intent(); i.setClassName("com.eurekateam.cameralightsensor", "com.eurekateam.cameralightsensor.CameraLightSensorService"); - i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(i); + context.startForegroundService(i); } } } diff --git a/universal7885-common/apps/CameraLightSensor/src/com/eurekateam/cameralightsensor/Camera2Service.java b/universal7885-common/apps/CameraLightSensor/src/com/eurekateam/cameralightsensor/Camera2Service.java deleted file mode 100755 index 704d399..0000000 --- a/universal7885-common/apps/CameraLightSensor/src/com/eurekateam/cameralightsensor/Camera2Service.java +++ /dev/null @@ -1,328 +0,0 @@ -package com.eurekateam.cameralightsensor; - -import static com.eurekateam.cameralightsensor.CameraLightSensorService.DEBUG; - -import android.annotation.NonNull; -import android.annotation.SuppressLint; -import android.app.Notification; -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Color; -import android.graphics.ImageFormat; -import android.hardware.camera2.CameraAccessException; -import android.hardware.camera2.CameraCaptureSession; -import android.hardware.camera2.CameraCharacteristics; -import android.hardware.camera2.CameraDevice; -import android.hardware.camera2.CameraManager; -import android.hardware.camera2.CaptureRequest; -import android.media.Image; -import android.media.ImageReader; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.provider.Settings; -import android.util.Log; - -import androidx.core.app.NotificationCompat; - -import java.nio.ByteBuffer; -import java.util.Collections; - -public class Camera2Service extends Service { - protected static final String TAG = Camera2Service.class.getSimpleName(); - protected static final int CAMERACHOICE = CameraCharacteristics.LENS_FACING_FRONT; - boolean destroy; - protected CameraDevice cameraDevice; - protected CameraCaptureSession session; - boolean isavail = true; - protected ImageReader imageReader; - private Context mContext; - private CameraManager manager; - private long mCaptureTime; - private final int DELAY = 5000; - - protected CameraDevice.StateCallback cameraStateCallback = new CameraDevice.StateCallback() { - @Override - public void onOpened(@NonNull CameraDevice camera) { - Log.d(TAG, "CameraDevice.StateCallback onOpened"); - cameraDevice = camera; - actOnReadyCameraDevice(); - } - - @Override - public void onDisconnected(@NonNull CameraDevice camera) { - Log.w(TAG, "CameraDevice.StateCallback onDisconnected"); - } - - @Override - public void onError(@NonNull CameraDevice camera, int error) { - Log.e(TAG, "CameraDevice.StateCallback onError " + error); - } - }; - - protected CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() { - - @Override - public void onReady(CameraCaptureSession session) { - if (!destroy) { - Camera2Service.this.session = session; - try { - if (createCaptureRequest() == null) return; - try { - session.capture(createCaptureRequest(), captureCallback, null); - } catch (CameraAccessException e) { - e.printStackTrace(); - } catch (IllegalStateException e) { - Log.w(TAG, "onReady: Session is NULL"); - } - } catch (Exception e) { - Log.e(TAG, "Camera is in use"); - e.printStackTrace(); - } - } - } - - - @Override - public void onConfigured(CameraCaptureSession session) { - - } - - @Override - public void onConfigureFailed(@NonNull CameraCaptureSession session) { - } - }; - - - protected ImageReader.OnImageAvailableListener onImageAvailableListener = reader -> { - if (DEBUG) Log.d(TAG, "onImageAvailable: Capturing"); - Image img = reader.acquireLatestImage(); - if (img != null) { - try { - processImage(img); - } catch (Settings.SettingNotFoundException | InterruptedException e) { - e.printStackTrace(); - } - img.close(); - if (DEBUG) - Log.d(TAG, "ImageReader.OnImageAvailableListener: Closing Camera and Sessions.."); - cameraDevice.close(); - session.close(); - } - }; - - @SuppressLint("MissingPermission") - public void readyCamera() { - manager = (CameraManager) getSystemService(CAMERA_SERVICE); - mCaptureTime = System.currentTimeMillis(); - try { - String pickedCamera = getCamera(manager); - manager.registerAvailabilityCallback(availabilityCallback, null); - manager.openCamera(pickedCamera, cameraStateCallback, null); - imageReader = ImageReader.newInstance(250, 250, ImageFormat.JPEG, 2 /* images buffered */); - imageReader.setOnImageAvailableListener(onImageAvailableListener, null); - if (DEBUG) Log.d(TAG, "imageReader created"); - } catch (CameraAccessException e) { - Log.e(TAG, e.getMessage()); - isavail = false; - } - } - - public String getCamera(CameraManager manager) { - try { - for (String cameraId : manager.getCameraIdList()) { - CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); - int cOrientation = characteristics.get(CameraCharacteristics.LENS_FACING); - if (cOrientation == CAMERACHOICE) { - return cameraId; - } - } - } catch (CameraAccessException e) { - e.printStackTrace(); - } - return null; - } - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if(DEBUG) Log.d(TAG, "onStartCommand flags " + flags + " startId " + startId); - destroy = false; - isavail = true; - startForeground(50, PushNotification()); - readyCamera(); - return START_NOT_STICKY; - } - - public Notification PushNotification() - { - NotificationManager nm = (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE); - NotificationChannel channel = new NotificationChannel( - mContext.getBasePackageName(), "CameraLightSensor", - NotificationManager.IMPORTANCE_LOW - ); - nm.createNotificationChannel(channel); - NotificationCompat.Builder builder = - new NotificationCompat.Builder(mContext, mContext.getBasePackageName()); - Intent notificationIntent = new Intent(mContext, Camera2Service.class); - PendingIntent contentIntent = PendingIntent.getActivity(mContext,50, - notificationIntent,PendingIntent.FLAG_IMMUTABLE); - - //set - builder.setContentIntent(contentIntent); - builder.setSmallIcon(R.drawable.ic_brightness); - builder.setContentTitle("Camera Light Sensor Service"); - builder.setChannelId(mContext.getBasePackageName()); - - return builder.build(); - } - - @Override - public void onCreate() { - if(DEBUG) Log.d(TAG, "onCreate service"); - mContext = getApplicationContext(); - startForeground(50, PushNotification()); - readyCamera(); - super.onCreate(); - } - - public void actOnReadyCameraDevice() { - try { - cameraDevice.createCaptureSession(Collections.singletonList(imageReader.getSurface()), sessionStateCallback, null); - } catch (CameraAccessException e) { - Log.e(TAG, e.getMessage()); - } - } - - @Override - public void onDestroy() { - cameraDevice.close(); - if (session != null && isavail) { - try { - session.abortCaptures(); - session.close(); - } catch (CameraAccessException e) { - Log.e(TAG, e.getMessage()); - } catch (IllegalStateException e2){ - Log.e(TAG, "Session Already Closed"); - } - - } - manager.unregisterAvailabilityCallback(availabilityCallback); - isavail = false; - destroy = true; - stopForeground(true); - } - - private void processImage(Image image) throws Settings.SettingNotFoundException, InterruptedException { - ByteBuffer buffer = image.getPlanes()[0].getBuffer(); - byte[] bytes = new byte[buffer.capacity()]; - buffer.get(bytes); - Bitmap bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null); - int brightness = calculateBrightnessEstimate(bitmapImage,5); - AdjustBrightness(brightness); - } - - protected CaptureRequest createCaptureRequest() { - try { - CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); - builder.addTarget(imageReader.getSurface()); - return builder.build(); - } catch (CameraAccessException e) { - Log.e(TAG, e.getMessage()); - return null; - } - } - CameraManager.AvailabilityCallback availabilityCallback = new CameraManager.AvailabilityCallback() { - @Override - public void onCameraOpened(String cameraId, String packageId) { - super.onCameraOpened(cameraId, packageId); - Log.i(TAG, "CameraManager.AvailabilityCallback: Camera " + cameraId - + " Opened by Package " + packageId); - if (packageId.equals(mContext.getBasePackageName())) return; - isavail = false; - } - - @Override - public void onCameraUnavailable(String cameraId) { - if (DEBUG) Log.i(TAG, "CameraManager.AvailabilityCallback : Camera NOT Available. "); - isavail = false; - super.onCameraUnavailable(cameraId); - } - - @Override - public void onCameraAvailable(String cameraId) { - if (DEBUG) Log.i(TAG, "CameraManager.AvailabilityCallback : Camera IS Available. "); - super.onCameraAvailable(cameraId); - } - - @Override - public void onCameraClosed(String cameraId) { - super.onCameraClosed(cameraId); - while (mCaptureTime + DELAY >= System.currentTimeMillis() && isavail) { - try { - Thread.sleep(1000); - if (DEBUG) Log.i(TAG, "CameraManager.AvailabilityCallback: " + - "Thread: Waiting..."); - isavail = false; - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - isavail = true; - Handler mHandler = new Handler(Looper.getMainLooper()); - mHandler.postDelayed(() -> { - if(isavail) readyCamera(); - },DELAY); - } - }; - CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() { - @Override - public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, long frameNumber) { - if (DEBUG) Log.d(TAG, "captureCallback: Closing Session"); - super.onCaptureSequenceCompleted(session, sequenceId, frameNumber); - cameraDevice.close(); - session.close(); - } - - }; - - @Override - public IBinder onBind(Intent intent) { - return null; - } - - public int calculateBrightnessEstimate(Bitmap bitmap, int pixelSpacing) { - int R = 0; int G = 0; int B = 0; - int height = bitmap.getHeight(); - int width = bitmap.getWidth(); - int n = 0; - int[] pixels = new int[width * height]; - bitmap.getPixels(pixels, 0, width, 0, 0, width, height); - for (int i = 0; i < pixels.length; i += pixelSpacing) { - int color = pixels[i]; - R += Color.red(color); - G += Color.green(color); - B += Color.blue(color); - n++; - } - return (R + B + G) / (n * 3); - } - private void AdjustBrightness(int brightness) throws Settings.SettingNotFoundException { - if (DEBUG) Log.i(TAG, "AdjustBrightness: Received Brightness Value " + brightness); - int oldbrightness = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS); - if (DEBUG) Log.i(TAG, "AdjustBrightness: Oldval = " + oldbrightness + " Newval = " + - brightness + " Adjusting.."); - int newbrightness = brightness; - if (newbrightness > 255){ - newbrightness = 255; - }else if (newbrightness < 0){ - newbrightness = 0; - } - Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, newbrightness); - } -} diff --git a/universal7885-common/apps/CameraLightSensor/src/com/eurekateam/cameralightsensor/CameraLightSensorService.java b/universal7885-common/apps/CameraLightSensor/src/com/eurekateam/cameralightsensor/CameraLightSensorService.java index d00d06e..7a797f5 100755 --- a/universal7885-common/apps/CameraLightSensor/src/com/eurekateam/cameralightsensor/CameraLightSensorService.java +++ b/universal7885-common/apps/CameraLightSensor/src/com/eurekateam/cameralightsensor/CameraLightSensorService.java @@ -1,49 +1,288 @@ package com.eurekateam.cameralightsensor; -import android.Manifest; -import android.app.Activity; +import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; import android.database.ContentObserver; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.ImageFormat; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CameraManager; +import android.hardware.camera2.CaptureRequest; +import android.media.Image; +import android.media.ImageReader; import android.net.Uri; -import android.os.Bundle; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; import android.os.PowerManager; +import android.os.SystemClock; import android.provider.Settings; import android.util.Log; +import androidx.core.app.NotificationCompat; +import androidx.core.content.ContextCompat; -public class CameraLightSensorService extends Activity { - private static final String TAG = "CameraLightSensor"; - static final boolean DEBUG = false; - Intent i; +import java.nio.ByteBuffer; +import java.util.Collections; + +public class CameraLightSensorService extends Service { + protected static final String TAG = CameraLightSensorService.class.getSimpleName(); + static final boolean DEBUG = true; IntentFilter screenStateFilter; private Context mContext; public ContentResolver contentResolver; private boolean mRegistered; + protected static final int CAMERA_CHOICE = CameraCharacteristics.LENS_FACING_FRONT; + boolean destroy; + protected CameraDevice cameraDevice; + protected CameraCaptureSession session; + volatile boolean avail = true; + protected ImageReader imageReader; + private CameraManager manager; + private final static int DELAY = 5 * 1000; // 5 Seconds private boolean mServiceStarted; + volatile private boolean mLock; + private boolean mThreadRunning; + + public Notification PushNotification() + { + NotificationManager nm = (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE); + NotificationChannel channel = new NotificationChannel( + mContext.getBasePackageName(), "CameraLightSensor", + NotificationManager.IMPORTANCE_LOW + ); + nm.createNotificationChannel(channel); + NotificationCompat.Builder builder = + new NotificationCompat.Builder(mContext, mContext.getBasePackageName()); + Intent notificationIntent = new Intent(mContext, CameraLightSensorService.class); + PendingIntent contentIntent = PendingIntent.getActivity(mContext,50, + notificationIntent,PendingIntent.FLAG_IMMUTABLE); + + //set + builder.setContentIntent(contentIntent); + builder.setSmallIcon(R.drawable.ic_brightness); + builder.setContentTitle("Camera Light Sensor Service"); + builder.setChannelId(mContext.getBasePackageName()); + + return builder.build(); + } @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - moveTaskToBack(true); + public void onDestroy() { + if (DEBUG) Log.d(TAG, "Destroying service"); + if(mRegistered) contentResolver.unregisterContentObserver(mSettingsObserver); + mRegistered = false; + cameraDevice.close(); + if (session != null && avail) { + try { + session.abortCaptures(); + session.close(); + } catch (CameraAccessException e) { + Log.e(TAG, e.getMessage()); + } catch (IllegalStateException e2){ + Log.e(TAG, "Session Already Closed"); + } + + } + manager.unregisterAvailabilityCallback(availabilityCallback); + avail = false; + destroy = true; + stopForeground(true); + super.onDestroy(); + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + private final BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { + onDisplayOn(); + mServiceStarted = true; + } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { + if (mServiceStarted) onDisplayOff(); + mServiceStarted = false; + } + } + }; + // Make a listener for settings + ContentObserver mSettingsObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + Log.i(TAG, "observer: Brightness Settings Changed"); + try { + if(Settings.System.getInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS_MODE) + == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC){ + registerReceiver(mScreenStateReceiver, screenStateFilter); + mRegistered = true; + onDisplayOn(); + }else{ + if(mRegistered) unregisterReceiver(mScreenStateReceiver); + mRegistered = false; + onDisplayOff(); + } + } catch (Settings.SettingNotFoundException e) { + e.printStackTrace(); + } + } + @Override + public boolean deliverSelfNotifications() { + return true; + } + }; + + private void onDisplayOn() { + if(DEBUG) Log.d(TAG, "Screen is on. Starting Service..."); + avail = true; + readyCamera(); + } + private void onDisplayOff(){ + if(DEBUG) Log.d(TAG, "Screen is off. Stopping Service..."); + thread.interrupt(); + avail = false; + mThreadRunning = false; + } + public static void BatteryOptimization(Context context){ + Intent intent = new Intent(); + String packageName = context.getPackageName(); + PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE); + if (!pm.isIgnoringBatteryOptimizations(packageName)) { + intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); + intent.setData(Uri.parse("package:" + packageName)); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + } + protected CameraDevice.StateCallback cameraStateCallback = new CameraDevice.StateCallback() { + @Override + public void onOpened(@NonNull CameraDevice camera) { + Log.d(TAG, "CameraDevice.StateCallback onOpened"); + cameraDevice = camera; + actOnReadyCameraDevice(); + } + + @Override + public void onDisconnected(@NonNull CameraDevice camera) { + Log.w(TAG, "CameraDevice.StateCallback onDisconnected"); + } + + @Override + public void onError(@NonNull CameraDevice camera, int error) { + Log.e(TAG, "CameraDevice.StateCallback onError " + error); + } + }; + + protected CameraCaptureSession.StateCallback sessionStateCallback = new CameraCaptureSession.StateCallback() { + + @Override + public void onReady(CameraCaptureSession session) { + if (!destroy) { + CameraLightSensorService.this.session = session; + try { + if (createCaptureRequest() == null) return; + try { + session.capture(createCaptureRequest(), captureCallback, null); + } catch (CameraAccessException e) { + e.printStackTrace(); + } catch (IllegalStateException e) { + Log.w(TAG, "onReady: Session is NULL"); + } + } catch (Exception e) { + Log.e(TAG, "Camera is in use"); + e.printStackTrace(); + } + } + } + + + @Override + public void onConfigured(CameraCaptureSession session) { + + } + + @Override + public void onConfigureFailed(@NonNull CameraCaptureSession session) { + } + }; + + + protected ImageReader.OnImageAvailableListener onImageAvailableListener = reader -> { + if (DEBUG) Log.d(TAG, "onImageAvailable: Capturing"); + Image img = reader.acquireLatestImage(); + if (img != null) { + try { + processImage(img); + } catch (Settings.SettingNotFoundException | InterruptedException e) { + e.printStackTrace(); + } + img.close(); + if (DEBUG) + Log.d(TAG, "ImageReader.OnImageAvailableListener: Closing Camera and Sessions.."); + cameraDevice.close(); + session.close(); + } + }; + + @SuppressLint("MissingPermission") + public void readyCamera() { + manager = (CameraManager) getSystemService(CAMERA_SERVICE); + try { + String pickedCamera = getCamera(manager); + manager.registerAvailabilityCallback(availabilityCallback, null); + manager.openCamera(pickedCamera, cameraStateCallback, null); + imageReader = ImageReader.newInstance(250, 250, ImageFormat.JPEG, 2 /* images buffered */); + imageReader.setOnImageAvailableListener(onImageAvailableListener, null); + if(!mThreadRunning){ + Thread mMyThread = new Thread(thread); + mMyThread.start(); + mThreadRunning = true; + } + if (DEBUG) Log.d(TAG, "imageReader created"); + } catch (CameraAccessException e) { + Log.e(TAG, e.getMessage()); + } + } + + public String getCamera(CameraManager manager) { + try { + for (String cameraId : manager.getCameraIdList()) { + CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); + int cOrientation = characteristics.get(CameraCharacteristics.LENS_FACING); + if (cOrientation == CAMERA_CHOICE) { + return cameraId; + } + } + } catch (CameraAccessException e) { + e.printStackTrace(); + } + return null; + } + @Override + public int onStartCommand(Intent intent, int flags, int startId) { mContext = getApplicationContext(); contentResolver = getContentResolver(); + startForeground(50, PushNotification(), ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA); BatteryOptimization(mContext); - i = new Intent(mContext, Camera2Service.class); - if (this.checkSelfPermission(Manifest.permission.CAMERA) == - PackageManager.PERMISSION_GRANTED) { - Log.d(TAG, "Permission Granted"); - } else { - // You can directly ask for the permission. - this.requestPermissions(new String[] { Manifest.permission.CAMERA }, - 1); - } mRegistered = false; screenStateFilter = new IntentFilter(Intent.ACTION_SCREEN_ON); screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF); @@ -57,71 +296,132 @@ public class CameraLightSensorService extends Activity { e.printStackTrace(); } Uri setting = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE); - contentResolver.registerContentObserver(setting, false, observer); + contentResolver.registerContentObserver(setting, false, mSettingsObserver); + if(DEBUG) Log.d(TAG, "onStartCommand flags " + flags + " startId " + startId); + destroy = false; + avail = true; + startForeground(50, PushNotification()); + return START_NOT_STICKY; + } - } @Override - public void onDestroy() { - if (DEBUG) Log.d(TAG, "Destroying service"); - mRegistered = false; - contentResolver.unregisterContentObserver(observer); - super.onDestroy(); + public void onCreate() { + if(DEBUG) Log.d(TAG, "onCreate service"); + mContext = getApplicationContext(); + startForeground(50, PushNotification()); + super.onCreate(); } - private final BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { - onDisplayOn(); - mServiceStarted = true; - } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { - if (mServiceStarted) onDisplayOff(); - mServiceStarted = false; - } + + public void actOnReadyCameraDevice() { + try { + cameraDevice.createCaptureSession(Collections.singletonList(imageReader.getSurface()), sessionStateCallback, null); + } catch (CameraAccessException e) { + Log.e(TAG, e.getMessage()); + mLock = false; } + } + private void processImage(Image image) throws Settings.SettingNotFoundException, InterruptedException { + ByteBuffer buffer = image.getPlanes()[0].getBuffer(); + byte[] bytes = new byte[buffer.capacity()]; + buffer.get(bytes); + Bitmap bitmapImage = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null); + int brightness = calculateBrightnessEstimate(bitmapImage,5); + AdjustBrightness(brightness); + } + + protected CaptureRequest createCaptureRequest() { + try { + CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); + builder.addTarget(imageReader.getSurface()); + return builder.build(); + } catch (CameraAccessException e) { + Log.e(TAG, e.getMessage()); + mLock = false; + return null; + } + } + CameraManager.AvailabilityCallback availabilityCallback = new CameraManager.AvailabilityCallback() { + @Override + public void onCameraOpened(String cameraId, String packageId) { + super.onCameraOpened(cameraId, packageId); + Log.i(TAG, "CameraManager.AvailabilityCallback: Camera " + cameraId + + " Opened by Package " + packageId); + mLock = true; + if (packageId.equals(mContext.getBasePackageName())) return; + avail = false; + } + + @Override + public void onCameraUnavailable(String cameraId) { + if (DEBUG) Log.i(TAG, "CameraManager.AvailabilityCallback : Camera NOT Available. "); + avail = false; + super.onCameraUnavailable(cameraId); + } + + @Override + public void onCameraAvailable(String cameraId) { + if (DEBUG) Log.i(TAG, "CameraManager.AvailabilityCallback : Camera IS Available. "); + avail = true; + mLock = false; + super.onCameraAvailable(cameraId); + } + + @Override + public void onCameraClosed(String cameraId) { + super.onCameraClosed(cameraId); + } + }; - // Make a listener - ContentObserver observer = new ContentObserver(new Handler(Looper.getMainLooper())) { + CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() { @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); - Log.i(TAG, "observer: Brightness Settings Changed"); - try { - if(Settings.System.getInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS_MODE) - == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC){ - registerReceiver(mScreenStateReceiver, screenStateFilter); - mRegistered = true; - mContext.startForegroundService(i); - }else{ - if(mRegistered) unregisterReceiver(mScreenStateReceiver); - mRegistered = false; - mContext.stopService(i); - } - } catch (Settings.SettingNotFoundException e) { - e.printStackTrace(); - } - } - @Override - public boolean deliverSelfNotifications() { - return true; + public void onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, long frameNumber) { + if (DEBUG) Log.d(TAG, "captureCallback: Closing Session"); + super.onCaptureSequenceCompleted(session, sequenceId, frameNumber); + cameraDevice.close(); + session.close(); } + }; - private void onDisplayOn() { - if(DEBUG) Log.d(TAG, "Screen is on. Starting Service..."); - mContext.startForegroundService(i); + + public int calculateBrightnessEstimate(Bitmap bitmap, int pixelSpacing) { + int R = 0; int G = 0; int B = 0; + int height = bitmap.getHeight(); + int width = bitmap.getWidth(); + int n = 0; + int[] pixels = new int[width * height]; + bitmap.getPixels(pixels, 0, width, 0, 0, width, height); + for (int i = 0; i < pixels.length; i += pixelSpacing) { + int color = pixels[i]; + R += Color.red(color); + G += Color.green(color); + B += Color.blue(color); + n++; + } + return (R + B + G) / (n * 3); } - private void onDisplayOff(){ - if(DEBUG) Log.d(TAG, "Screen is off. Stopping Service..."); - mContext.stopService(i); + private void AdjustBrightness(int brightness) throws Settings.SettingNotFoundException { + if (DEBUG) Log.i(TAG, "AdjustBrightness: Received Brightness Value " + brightness); + int oldbrightness = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS); + if (DEBUG) Log.i(TAG, "AdjustBrightness: OldVal = " + oldbrightness + " NewVal = " + + brightness + " Adjusting.."); + int newbrightness = brightness; + if (newbrightness > 255){ + newbrightness = 255; + }else if (newbrightness < 0){ + newbrightness = 0; + } + Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, newbrightness); } - public static void BatteryOptimization(Context context){ - Intent intent = new Intent(); - String packageName = context.getPackageName(); - PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE); - if (!pm.isIgnoringBatteryOptimizations(packageName)) { - intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); - intent.setData(Uri.parse("package:" + packageName)); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); + Thread thread = new Thread(() -> { + while (!Thread.currentThread().isInterrupted()) { + if (avail && !mLock) { + SystemClock.sleep(DELAY); + ContextCompat.getMainExecutor(mContext).execute(() -> { + if (avail) readyCamera(); + }); } - } + } + + }); } + diff --git a/universal7885-common/vendor_detect/prebuilt b/universal7885-common/vendor_detect/prebuilt deleted file mode 100755 index b950a271358797ef2e64428edd9a4aefd873314e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50800 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 J=9QPU{x`kyD!%{#