Loading services/core/java/com/android/server/camera/CameraServiceProxy.java +179 −0 Original line number Diff line number Diff line Loading @@ -15,17 +15,33 @@ */ package com.android.server.camera; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.os.Build.VERSION_CODES.M; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.TaskStackListener; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.CameraSessionStats; import android.hardware.CameraStreamStats; import android.hardware.ICameraService; import android.hardware.ICameraServiceProxy; import android.hardware.camera2.CameraMetadata; import android.hardware.display.DisplayManager; import android.media.AudioManager; import android.metrics.LogMaker; import android.nfc.INfcAdapter; Loading @@ -41,7 +57,10 @@ import android.os.UserManager; import android.stats.camera.nano.CameraProtos.CameraStreamProto; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.Slog; import android.view.Display; import android.view.Surface; import com.android.internal.annotations.GuardedBy; import com.android.framework.protobuf.nano.MessageNano; Loading @@ -61,6 +80,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; Loading Loading @@ -203,6 +223,63 @@ public class CameraServiceProxy extends SystemService } } private final TaskStateHandler mTaskStackListener = new TaskStateHandler(); private final class TaskInfo { private int frontTaskId; private boolean isResizeable; private boolean isFixedOrientationLandscape; private boolean isFixedOrientationPortrait; private int displayId; } private final class TaskStateHandler extends TaskStackListener { private final Object mMapLock = new Object(); // maps the current top level task id to its corresponding package name @GuardedBy("mMapLock") private final ArrayMap<String, TaskInfo> mTaskInfoMap = new ArrayMap<>(); @Override public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) throws RemoteException { synchronized (mMapLock) { TaskInfo info = new TaskInfo(); info.frontTaskId = taskInfo.taskId; info.isResizeable = taskInfo.isResizeable; info.displayId = taskInfo.displayId; info.isFixedOrientationLandscape = ActivityInfo.isFixedOrientationLandscape( taskInfo.topActivityInfo.screenOrientation); info.isFixedOrientationPortrait = ActivityInfo.isFixedOrientationPortrait( taskInfo.topActivityInfo.screenOrientation); mTaskInfoMap.put(taskInfo.topActivityInfo.packageName, info); } } @Override public void onTaskRemoved(int taskId) throws RemoteException { synchronized (mMapLock) { for (Map.Entry<String, TaskInfo> entry : mTaskInfoMap.entrySet()){ if (entry.getValue().frontTaskId == taskId) { mTaskInfoMap.remove(entry.getKey()); break; } } } } public @Nullable TaskInfo getFrontTaskInfo(String packageName) { synchronized (mMapLock) { if (mTaskInfoMap.containsKey(packageName)) { return mTaskInfoMap.get(packageName); } } Log.e(TAG, "Top task with package name: " + packageName + " not found!"); return null; } }; private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading @@ -229,6 +306,102 @@ public class CameraServiceProxy extends SystemService }; private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() { private boolean isMOrBelow(Context ctx, String packageName) { try { return ctx.getPackageManager().getPackageInfo( packageName, 0).applicationInfo.targetSdkVersion <= M; } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG,"Package name not found!"); } return false; } /** * Gets whether crop-rotate-scale is needed. */ private boolean getNeedCropRotateScale(Context ctx, String packageName, @Nullable TaskInfo taskInfo, int sensorOrientation, int lensFacing) { if (taskInfo == null) { return false; } // External cameras do not need crop-rotate-scale. if (lensFacing != CameraMetadata.LENS_FACING_FRONT && lensFacing != CameraMetadata.LENS_FACING_BACK) { Log.v(TAG, "lensFacing=" + lensFacing + ". Crop-rotate-scale is disabled."); return false; } // Only enable the crop-rotate-scale workaround if the app targets M or below and is not // resizeable. if ((ctx != null) && !isMOrBelow(ctx, packageName) && taskInfo.isResizeable) { Slog.v(TAG, "The activity is N or above and claims to support resizeable-activity. " + "Crop-rotate-scale is disabled."); return false; } DisplayManager displayManager = ctx.getSystemService(DisplayManager.class); Display display = displayManager.getDisplay(taskInfo.displayId); int rotation = display.getRotation(); int rotationDegree = 0; switch (rotation) { case Surface.ROTATION_0: rotationDegree = 0; break; case Surface.ROTATION_90: rotationDegree = 90; break; case Surface.ROTATION_180: rotationDegree = 180; break; case Surface.ROTATION_270: rotationDegree = 270; break; } // Here we only need to know whether the camera is landscape or portrait. Therefore we // don't need to consider whether it is a front or back camera. The formula works for // both. boolean landscapeCamera = ((rotationDegree + sensorOrientation) % 180 == 0); Slog.v(TAG, "Display.getRotation()=" + rotationDegree + " CameraCharacteristics.SENSOR_ORIENTATION=" + sensorOrientation + " isFixedOrientationPortrait=" + taskInfo.isFixedOrientationPortrait + " isFixedOrientationLandscape=" + taskInfo.isFixedOrientationLandscape); // We need to do crop-rotate-scale when camera is landscape and activity is portrait or // vice versa. if ((taskInfo.isFixedOrientationPortrait && landscapeCamera) || (taskInfo.isFixedOrientationLandscape && !landscapeCamera)) { return true; } else { return false; } } @Override public boolean isRotateAndCropOverrideNeeded(String packageName, int sensorOrientation, int lensFacing) { if (Binder.getCallingUid() != Process.CAMERASERVER_UID) { Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + " doesn't match expected " + " camera service UID!"); return false; } // A few remaining todos: // 1) Do the same check when working in WM compatible mode. The sequence needs // to be adjusted and use orientation events as triggers for all active camera // clients. // 2) Modify the sensor orientation in camera characteristics along with any 3A regions // in capture requests/results to account for thea physical rotation. The former // is somewhat tricky as it assumes that camera clients always check for the current // value by retrieving the camera characteristics from the camera device. return getNeedCropRotateScale(mContext, packageName, mTaskStackListener.getFrontTaskInfo(packageName), sensorOrientation, lensFacing); } @Override public void pingForUserUpdate() { if (Binder.getCallingUid() != Process.CAMERASERVER_UID) { Loading Loading @@ -350,6 +523,12 @@ public class CameraServiceProxy extends SystemService publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy); publishLocalService(CameraServiceProxy.class, this); try { ActivityTaskManager.getService().registerTaskStackListener(mTaskStackListener); } catch (RemoteException e) { Log.e(TAG, "Failed to register task stack listener!"); } CameraStatsJobService.schedule(mContext); } Loading Loading
services/core/java/com/android/server/camera/CameraServiceProxy.java +179 −0 Original line number Diff line number Diff line Loading @@ -15,17 +15,33 @@ */ package com.android.server.camera; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; import static android.os.Build.VERSION_CODES.M; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.TaskStackListener; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Rect; import android.hardware.CameraSessionStats; import android.hardware.CameraStreamStats; import android.hardware.ICameraService; import android.hardware.ICameraServiceProxy; import android.hardware.camera2.CameraMetadata; import android.hardware.display.DisplayManager; import android.media.AudioManager; import android.metrics.LogMaker; import android.nfc.INfcAdapter; Loading @@ -41,7 +57,10 @@ import android.os.UserManager; import android.stats.camera.nano.CameraProtos.CameraStreamProto; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.Slog; import android.view.Display; import android.view.Surface; import com.android.internal.annotations.GuardedBy; import com.android.framework.protobuf.nano.MessageNano; Loading @@ -61,6 +80,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; Loading Loading @@ -203,6 +223,63 @@ public class CameraServiceProxy extends SystemService } } private final TaskStateHandler mTaskStackListener = new TaskStateHandler(); private final class TaskInfo { private int frontTaskId; private boolean isResizeable; private boolean isFixedOrientationLandscape; private boolean isFixedOrientationPortrait; private int displayId; } private final class TaskStateHandler extends TaskStackListener { private final Object mMapLock = new Object(); // maps the current top level task id to its corresponding package name @GuardedBy("mMapLock") private final ArrayMap<String, TaskInfo> mTaskInfoMap = new ArrayMap<>(); @Override public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) throws RemoteException { synchronized (mMapLock) { TaskInfo info = new TaskInfo(); info.frontTaskId = taskInfo.taskId; info.isResizeable = taskInfo.isResizeable; info.displayId = taskInfo.displayId; info.isFixedOrientationLandscape = ActivityInfo.isFixedOrientationLandscape( taskInfo.topActivityInfo.screenOrientation); info.isFixedOrientationPortrait = ActivityInfo.isFixedOrientationPortrait( taskInfo.topActivityInfo.screenOrientation); mTaskInfoMap.put(taskInfo.topActivityInfo.packageName, info); } } @Override public void onTaskRemoved(int taskId) throws RemoteException { synchronized (mMapLock) { for (Map.Entry<String, TaskInfo> entry : mTaskInfoMap.entrySet()){ if (entry.getValue().frontTaskId == taskId) { mTaskInfoMap.remove(entry.getKey()); break; } } } } public @Nullable TaskInfo getFrontTaskInfo(String packageName) { synchronized (mMapLock) { if (mTaskInfoMap.containsKey(packageName)) { return mTaskInfoMap.get(packageName); } } Log.e(TAG, "Top task with package name: " + packageName + " not found!"); return null; } }; private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading @@ -229,6 +306,102 @@ public class CameraServiceProxy extends SystemService }; private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() { private boolean isMOrBelow(Context ctx, String packageName) { try { return ctx.getPackageManager().getPackageInfo( packageName, 0).applicationInfo.targetSdkVersion <= M; } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG,"Package name not found!"); } return false; } /** * Gets whether crop-rotate-scale is needed. */ private boolean getNeedCropRotateScale(Context ctx, String packageName, @Nullable TaskInfo taskInfo, int sensorOrientation, int lensFacing) { if (taskInfo == null) { return false; } // External cameras do not need crop-rotate-scale. if (lensFacing != CameraMetadata.LENS_FACING_FRONT && lensFacing != CameraMetadata.LENS_FACING_BACK) { Log.v(TAG, "lensFacing=" + lensFacing + ". Crop-rotate-scale is disabled."); return false; } // Only enable the crop-rotate-scale workaround if the app targets M or below and is not // resizeable. if ((ctx != null) && !isMOrBelow(ctx, packageName) && taskInfo.isResizeable) { Slog.v(TAG, "The activity is N or above and claims to support resizeable-activity. " + "Crop-rotate-scale is disabled."); return false; } DisplayManager displayManager = ctx.getSystemService(DisplayManager.class); Display display = displayManager.getDisplay(taskInfo.displayId); int rotation = display.getRotation(); int rotationDegree = 0; switch (rotation) { case Surface.ROTATION_0: rotationDegree = 0; break; case Surface.ROTATION_90: rotationDegree = 90; break; case Surface.ROTATION_180: rotationDegree = 180; break; case Surface.ROTATION_270: rotationDegree = 270; break; } // Here we only need to know whether the camera is landscape or portrait. Therefore we // don't need to consider whether it is a front or back camera. The formula works for // both. boolean landscapeCamera = ((rotationDegree + sensorOrientation) % 180 == 0); Slog.v(TAG, "Display.getRotation()=" + rotationDegree + " CameraCharacteristics.SENSOR_ORIENTATION=" + sensorOrientation + " isFixedOrientationPortrait=" + taskInfo.isFixedOrientationPortrait + " isFixedOrientationLandscape=" + taskInfo.isFixedOrientationLandscape); // We need to do crop-rotate-scale when camera is landscape and activity is portrait or // vice versa. if ((taskInfo.isFixedOrientationPortrait && landscapeCamera) || (taskInfo.isFixedOrientationLandscape && !landscapeCamera)) { return true; } else { return false; } } @Override public boolean isRotateAndCropOverrideNeeded(String packageName, int sensorOrientation, int lensFacing) { if (Binder.getCallingUid() != Process.CAMERASERVER_UID) { Slog.e(TAG, "Calling UID: " + Binder.getCallingUid() + " doesn't match expected " + " camera service UID!"); return false; } // A few remaining todos: // 1) Do the same check when working in WM compatible mode. The sequence needs // to be adjusted and use orientation events as triggers for all active camera // clients. // 2) Modify the sensor orientation in camera characteristics along with any 3A regions // in capture requests/results to account for thea physical rotation. The former // is somewhat tricky as it assumes that camera clients always check for the current // value by retrieving the camera characteristics from the camera device. return getNeedCropRotateScale(mContext, packageName, mTaskStackListener.getFrontTaskInfo(packageName), sensorOrientation, lensFacing); } @Override public void pingForUserUpdate() { if (Binder.getCallingUid() != Process.CAMERASERVER_UID) { Loading Loading @@ -350,6 +523,12 @@ public class CameraServiceProxy extends SystemService publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy); publishLocalService(CameraServiceProxy.class, this); try { ActivityTaskManager.getService().registerTaskStackListener(mTaskStackListener); } catch (RemoteException e) { Log.e(TAG, "Failed to register task stack listener!"); } CameraStatsJobService.schedule(mContext); } Loading