Merge "Camera: Connect activity resizing state to camera service" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-03-25 04:12:39 +00:00
committed by Android (Google) Code Review

View File

@@ -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;
@@ -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;
@@ -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;
@@ -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) {
@@ -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) {
@@ -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);
}