Merge "refactor to allow more code reuse Merge from pi-car-dev to master Bug: 110376110 Test: Tested on device Change-Id: Ibfd85571b72d0bbc9277a1a68245fdac78fe9cc4"
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 32c6898..60e4ce2 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3136,12 +3136,26 @@
* the following code snippet can be used:</p>
* <pre><code>// Returns true if the device supports the required hardware level, or better.
* boolean isHardwareLevelSupported(CameraCharacteristics c, int requiredLevel) {
+ * final int[] sortedHwLevels = {
+ * CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
+ * CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL,
+ * CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
+ * CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
+ * CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3
+ * };
* int deviceLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
- * if (deviceLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
- * return requiredLevel == deviceLevel;
+ * if (requiredLevel == deviceLevel) {
+ * return true;
* }
- * // deviceLevel is not LEGACY, can use numerical sort
- * return requiredLevel <= deviceLevel;
+ *
+ * for (int sortedlevel : sortedHwLevels) {
+ * if (sortedlevel == requiredLevel) {
+ * return true;
+ * } else if (sortedlevel == deviceLevel) {
+ * return false;
+ * }
+ * }
+ * return false; // Should never reach here
* }
* </code></pre>
* <p>At a high level, the levels are:</p>
@@ -3155,6 +3169,8 @@
* post-processing settings, and image capture at a high rate.</li>
* <li><code>LEVEL_3</code> devices additionally support YUV reprocessing and RAW image capture, along
* with additional output stream configurations.</li>
+ * <li><code>EXTERNAL</code> devices are similar to <code>LIMITED</code> devices with exceptions like some sensor or
+ * lens information not reorted or less stable framerates.</li>
* </ul>
* <p>See the individual level enums for full descriptions of the supported capabilities. The
* {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} entry describes the device's capabilities at a
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index f47d464..ce88697 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -44,19 +44,27 @@
* {@link android.Manifest.permission#CAMERA Camera} permission in its manifest
* in order to access camera devices.</p>
*
- * <p>A given camera device may provide support at one of two levels: limited or
- * full. If a device only supports the limited level, then Camera2 exposes a
- * feature set that is roughly equivalent to the older
+ * <p>A given camera device may provide support at one of several levels defined
+ * in {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}.
+ * If a device supports {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY} level,
+ * the camera device is running in backward compatibility mode and has minimum camera2 API support.
+ * If a device supports the {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}
+ * level, then Camera2 exposes a feature set that is roughly equivalent to the older
* {@link android.hardware.Camera Camera} API, although with a cleaner and more
- * efficient interface. Devices that implement the full level of support
+ * efficient interface.
+ * If a device supports the {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL EXTERNAL}
+ * level, then the device is a removable camera that provides similar but slightly less features
+ * as the {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} level.
+ * Devices that implement the {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} or
+ * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_3 LEVEL3} level of support
* provide substantially improved capabilities over the older camera
- * API. Applications that target the limited level devices will run unchanged on
- * the full-level devices; if your application requires a full-level device for
+ * API. If your application requires a full-level device for
* proper operation, declare the "android.hardware.camera.level.full" feature in your
* manifest.</p>
*
* @see CameraManager#openCamera
* @see android.Manifest.permission#CAMERA
+ * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
*/
public abstract class CameraDevice implements AutoCloseable {
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 504f840..7840fd0 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -23,6 +23,7 @@
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
+import android.view.Surface;
import android.view.SurfaceControl;
/**
@@ -62,6 +63,15 @@
public abstract boolean isProximitySensorAvailable();
/**
+ * Take a screenshot of the specified display into the provided {@link Surface}.
+ *
+ * @param displayId The display id to take the screenshot of.
+ * @param outSurface The {@link Surface} to take the screenshot into.
+ * @return True if the screenshot is taken.
+ */
+ public abstract boolean screenshot(int displayId, Surface outSurface);
+
+ /**
* Returns information about the specified logical display.
*
* @param displayId The logical display id.
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index e9472fa..13425e5 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -77,7 +77,11 @@
final Point size = new Point();
final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
try {
- wm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, size);
+ final Display display = context.getDisplay();
+ final int displayId = display != null
+ ? display.getDisplayId()
+ : Display.DEFAULT_DISPLAY;
+ wm.getInitialDisplaySize(displayId, size);
return size.x < size.y ?
Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
} catch (RemoteException e) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 376d16b..2da0818 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -109,6 +109,7 @@
import com.android.internal.util.IntPair;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
+import com.android.server.SystemService;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -260,6 +261,25 @@
return getUserStateLocked(mCurrentUserId);
}
+ public static final class Lifecycle extends SystemService {
+ private final AccessibilityManagerService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ mService = new AccessibilityManagerService(context);
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.ACCESSIBILITY_SERVICE, mService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ mService.onBootPhase(phase);
+ }
+ }
+
/**
* Creates a new instance.
*
@@ -296,6 +316,14 @@
return mFingerprintGestureDispatcher;
}
+ private void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
+ mAppWidgetService = LocalServices.getService(AppWidgetManagerInternal.class);
+ }
+ }
+ }
+
private UserState getUserState(int userId) {
synchronized (mLock) {
return getUserStateLocked(userId);
@@ -2684,16 +2712,6 @@
}
}
- private AppWidgetManagerInternal getAppWidgetManager() {
- synchronized (mLock) {
- if (mAppWidgetService == null
- && mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
- mAppWidgetService = LocalServices.getService(AppWidgetManagerInternal.class);
- }
- return mAppWidgetService;
- }
- }
-
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
@@ -3022,8 +3040,7 @@
return packageName.toString();
}
// Appwidget hosts get to pass packages for widgets they host
- final AppWidgetManagerInternal appWidgetManager = getAppWidgetManager();
- if (appWidgetManager != null && ArrayUtils.contains(appWidgetManager
+ if (mAppWidgetService != null && ArrayUtils.contains(mAppWidgetService
.getHostedWidgetPackages(resolvedUid), packageNameStr)) {
return packageName.toString();
}
@@ -3051,9 +3068,8 @@
// IMPORTANT: The target package is already vetted to be in the target UID
String[] uidPackages = new String[]{targetPackage};
// Appwidget hosts get to pass packages for widgets they host
- final AppWidgetManagerInternal appWidgetManager = getAppWidgetManager();
- if (appWidgetManager != null) {
- final ArraySet<String> widgetPackages = appWidgetManager
+ if (mAppWidgetService != null) {
+ final ArraySet<String> widgetPackages = mAppWidgetService
.getHostedWidgetPackages(targetUid);
if (widgetPackages != null && !widgetPackages.isEmpty()) {
final String[] validPackages = new String[uidPackages.length
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 0a77269..75b3556 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2165,6 +2165,24 @@
}
@Override
+ public boolean screenshot(int displayId, Surface outSurface) {
+ synchronized (mSyncRoot) {
+ final LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display != null) {
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ if (device != null) {
+ final IBinder token = device.getDisplayTokenLocked();
+ if (token != null) {
+ SurfaceControl.screenshot(token, outSurface);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
public DisplayInfo getDisplayInfo(int displayId) {
return getDisplayInfoInternal(displayId, Process.myUid());
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e6195b4..883e939 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -631,8 +631,10 @@
int mPointerLocationMode = 0; // guarded by mLock
- // The last window we were told about in focusChanged.
+ // The windows we were told about in focusChanged.
WindowState mFocusedWindow;
+ WindowState mLastFocusedWindow;
+
IApplicationToken mFocusedApp;
PointerLocationView mPointerLocationView;
@@ -3334,6 +3336,9 @@
mNavigationBar = null;
mNavigationBarController.setWindow(null);
}
+ if (mLastFocusedWindow == win) {
+ mLastFocusedWindow = null;
+ }
mScreenDecorWindows.remove(win);
}
@@ -5879,7 +5884,8 @@
@Override
public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
mFocusedWindow = newFocus;
- if ((updateSystemUiVisibilityLw()&SYSTEM_UI_CHANGING_LAYOUT) != 0) {
+ mLastFocusedWindow = lastFocus;
+ if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
// If the navigation bar has been hidden or shown, we need to do another
// layout pass to update that window.
return FINISH_LAYOUT_REDO_LAYOUT;
@@ -8105,10 +8111,19 @@
if (winCandidate == null) {
return 0;
}
+
+ // The immersive mode confirmation should never affect the system bar visibility, otherwise
+ // it will unhide the navigation bar and hide itself.
if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
- // The immersive mode confirmation should never affect the system bar visibility,
- // otherwise it will unhide the navigation bar and hide itself.
- winCandidate = isStatusBarKeyguard() ? mStatusBar : mTopFullscreenOpaqueWindowState;
+
+ // The immersive mode confirmation took the focus from mLastFocusedWindow which was
+ // controlling the system ui visibility. So if mLastFocusedWindow can still receive
+ // keys, we let it keep controlling the visibility.
+ final boolean lastFocusCanReceiveKeys =
+ (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
+ winCandidate = isStatusBarKeyguard() ? mStatusBar
+ : lastFocusCanReceiveKeys ? mLastFocusedWindow
+ : mTopFullscreenOpaqueWindowState;
if (winCandidate == null) {
return 0;
}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 1ebbe3ac..7ea6200 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -491,6 +491,9 @@
*/
boolean canAcquireSleepToken();
+ /** @return true if this window desires key events. */
+ boolean canReceiveKeys();
+
/**
* Writes {@link com.android.server.wm.IdentifierProto} to stream.
*/
diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java
index 1977e12..fff1fa4 100644
--- a/services/core/java/com/android/server/wm/BlackFrame.java
+++ b/services/core/java/com/android/server/wm/BlackFrame.java
@@ -56,6 +56,7 @@
.setParent(null) // TODO: Work-around for b/69259549
.build();
+ transaction.setLayerStack(surface, dc.getDisplayId());
transaction.setAlpha(surface, 1);
transaction.setLayer(surface, layer);
transaction.show(surface);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0ca8e1a..efe4d6f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -303,6 +303,7 @@
// Accessed directly by all users.
private boolean mLayoutNeeded;
int pendingLayoutChanges;
+ int mDeferredRotationPauseCount;
// TODO(multi-display): remove some of the usages.
boolean isDefaultDisplay;
/**
@@ -942,6 +943,36 @@
}
/**
+ * Temporarily pauses rotation changes until resumed.
+ *
+ * This can be used to prevent rotation changes from occurring while the user is
+ * performing certain operations, such as drag and drop.
+ *
+ * This call nests and must be matched by an equal number of calls to
+ * {@link #resumeRotationLocked}.
+ */
+ void pauseRotationLocked() {
+ mDeferredRotationPauseCount++;
+ }
+
+ /**
+ * Resumes normal rotation changes after being paused.
+ */
+ void resumeRotationLocked() {
+ if (mDeferredRotationPauseCount <= 0) {
+ return;
+ }
+
+ mDeferredRotationPauseCount--;
+ if (mDeferredRotationPauseCount == 0) {
+ final boolean changed = updateRotationUnchecked();
+ if (changed) {
+ mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, mDisplayId).sendToTarget();
+ }
+ }
+ }
+
+ /**
* Update rotation of the display.
*
* @return {@code true} if the rotation has been changed. In this case YOU MUST CALL
@@ -964,7 +995,7 @@
boolean updateRotationUnchecked(boolean forceUpdate) {
ScreenRotationAnimation screenRotationAnimation;
if (!forceUpdate) {
- if (mService.mDeferredRotationPauseCount > 0) {
+ if (mDeferredRotationPauseCount > 0) {
// Rotation updates have been paused temporarily. Defer the update until
// updates have been resumed.
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
@@ -1065,9 +1096,8 @@
}
mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
- mService.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT);
- mService.mH.sendEmptyMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
- WINDOW_FREEZE_TIMEOUT_DURATION);
+ mService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
+ this, WINDOW_FREEZE_TIMEOUT_DURATION);
setLayoutNeeded();
final int[] anim = new int[2];
@@ -1124,9 +1154,8 @@
}, true /* traverseTopToBottom */);
if (rotateSeamlessly) {
- mService.mH.removeMessages(WindowManagerService.H.SEAMLESS_ROTATION_TIMEOUT);
- mService.mH.sendEmptyMessageDelayed(WindowManagerService.H.SEAMLESS_ROTATION_TIMEOUT,
- SEAMLESS_ROTATION_TIMEOUT_DURATION);
+ mService.mH.sendNewMessageDelayed(WindowManagerService.H.SEAMLESS_ROTATION_TIMEOUT,
+ this, SEAMLESS_ROTATION_TIMEOUT_DURATION);
}
for (int i = mService.mRotationWatchers.size() - 1; i >= 0; i--) {
@@ -2282,6 +2311,8 @@
pw.println();
pw.print(prefix); pw.print("mLayoutSeq="); pw.println(mLayoutSeq);
+ pw.print(prefix);
+ pw.print("mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
pw.println();
pw.println(prefix + "Application tokens in top down Z order:");
@@ -2876,7 +2907,7 @@
mWallpaperController.adjustWallpaperWindows(this);
}
- if (isDefaultDisplay && (pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
+ if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
if (mService.updateOrientationFromAppTokensLocked(mDisplayId)) {
setLayoutNeeded();
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index fc370d9..f42e979 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -151,6 +151,7 @@
mDragState.mUid = callerUid;
mDragState.mOriginalAlpha = alpha;
mDragState.mToken = dragToken;
+ mDragState.mDisplayContent = displayContent;
final Display display = displayContent.getDisplay();
if (!mCallback.get().registerInputChannel(
@@ -160,7 +161,6 @@
return null;
}
- mDragState.mDisplayContent = displayContent;
mDragState.mData = data;
mDragState.broadcastDragStartedLocked(touchX, touchY);
mDragState.overridePointerIconLocked(touchSource);
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 1ac9b88..d4046e9 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -255,7 +255,7 @@
if (DEBUG_ORIENTATION) {
Slog.d(TAG_WM, "Pausing rotation during drag");
}
- mService.pauseRotationLocked();
+ mDisplayContent.pauseRotationLocked();
}
void tearDown() {
@@ -274,7 +274,7 @@
if (DEBUG_ORIENTATION) {
Slog.d(TAG_WM, "Resuming rotation after drag");
}
- mService.resumeRotationLocked();
+ mDisplayContent.resumeRotationLocked();
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index a709c55..2be4001 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -746,22 +746,7 @@
if (mUpdateRotation) {
if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
- // TODO(multi-display): Update rotation for different displays separately.
- final int displayId = defaultDisplay.getDisplayId();
- if (defaultDisplay.updateRotationUnchecked()) {
- mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget();
- } else {
- mUpdateRotation = false;
- }
- // Update rotation of VR virtual display separately. Currently this is the only kind of
- // secondary display that can be rotated because of the single-display limitations in
- // PhoneWindowManager.
- final DisplayContent vrDisplay = mService.mVr2dDisplayId != INVALID_DISPLAY
- ? getDisplayContent(mService.mVr2dDisplayId) : null;
- if (vrDisplay != null && vrDisplay.updateRotationUnchecked()) {
- mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, mService.mVr2dDisplayId)
- .sendToTarget();
- }
+ mUpdateRotation = updateRotationUnchecked();
}
if (mService.mWaitingForDrawnCallback != null ||
@@ -958,6 +943,19 @@
return displayHasContent;
}
+ boolean updateRotationUnchecked() {
+ boolean changed = false;
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ final DisplayContent displayContent = mChildren.get(i);
+ if (displayContent.updateRotationUnchecked()) {
+ changed = true;
+ mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayContent.getDisplayId())
+ .sendToTarget();
+ }
+ }
+ return changed;
+ }
+
boolean copyAnimToLayoutParams() {
boolean doRequest = false;
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index fa8a5c6..2f189a6 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -268,24 +268,18 @@
.setSecure(isSecure)
.build();
- // capture a screenshot into the surface we just created
- // TODO(multidisplay): we should use the proper display
- final int displayId = SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN;
- final IBinder displayHandle = SurfaceControl.getBuiltInDisplay(displayId);
- // This null check below is to guard a race condition where WMS didn't have a chance to
- // respond to display disconnection before handling rotation , that surfaceflinger may
- // return a null handle here because it doesn't think that display is valid anymore.
- if (displayHandle != null) {
- Surface sur = new Surface();
- sur.copyFrom(mSurfaceControl);
- SurfaceControl.screenshot(displayHandle, sur);
+ // Capture a screenshot into the surface we just created.
+ final int displayId = display.getDisplayId();
+ final Surface surface = new Surface();
+ surface.copyFrom(mSurfaceControl);
+ if (mService.mDisplayManagerInternal.screenshot(displayId, surface)) {
t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
t.setAlpha(mSurfaceControl, 0);
t.show(mSurfaceControl);
- sur.destroy();
} else {
- Slog.w(TAG, "Built-in display " + displayId + " is null.");
+ Slog.w(TAG, "Unable to take screenshot of display " + displayId);
}
+ surface.destroy();
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate freeze surface", e);
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 30f46a0..bd7e61c 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -97,7 +97,7 @@
private final WindowManagerService mService;
private final IActivityTaskManager mActivityManager;
private WindowPositionerEventReceiver mInputEventReceiver;
- private Display mDisplay;
+ private DisplayContent mDisplayContent;
private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
private Rect mTmpRect = new Rect();
private int mSideMargin;
@@ -250,8 +250,8 @@
return;
}
- mDisplay = display;
- mDisplay.getMetrics(mDisplayMetrics);
+ mDisplayContent = displayContent;
+ display.getMetrics(mDisplayMetrics);
final InputChannel[] channels = InputChannel.openInputChannelPair(TAG);
mServerChannel = channels[0];
mClientChannel = channels[1];
@@ -267,7 +267,7 @@
WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, null, null,
- mDisplay.getDisplayId());
+ display.getDisplayId());
mDragWindowHandle.name = TAG;
mDragWindowHandle.inputChannel = mServerChannel;
mDragWindowHandle.layer = mService.getDragLayerLocked();
@@ -292,7 +292,7 @@
mDragWindowHandle.frameLeft = 0;
mDragWindowHandle.frameTop = 0;
final Point p = new Point();
- mDisplay.getRealSize(p);
+ display.getRealSize(p);
mDragWindowHandle.frameRight = p.x;
mDragWindowHandle.frameBottom = p.y;
@@ -300,12 +300,12 @@
if (DEBUG_ORIENTATION) {
Slog.d(TAG, "Pausing rotation during re-position");
}
- mService.pauseRotationLocked();
+ mDisplayContent.pauseRotationLocked();
mSideMargin = dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics);
mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
- mDisplay.getRealSize(mMaxVisibleSize);
+ display.getRealSize(mMaxVisibleSize);
mDragEnded = false;
}
@@ -331,14 +331,14 @@
mDragWindowHandle = null;
mDragApplicationHandle = null;
- mDisplay = null;
mDragEnded = true;
// Resume rotations after a drag.
if (DEBUG_ORIENTATION) {
Slog.d(TAG, "Resuming rotation after re-position");
}
- mService.resumeRotationLocked();
+ mDisplayContent.resumeRotationLocked();
+ mDisplayContent = null;
}
void startDrag(WindowState win, boolean resize, boolean preserveOrientation, float startX,
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 736aec7..f315999 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -583,7 +583,6 @@
}
ArrayList<RotationWatcher> mRotationWatchers = new ArrayList<>();
- int mDeferredRotationPauseCount;
final WallpaperVisibilityListeners mWallpaperVisibilityListeners =
new WallpaperVisibilityListeners();
@@ -3823,37 +3822,6 @@
updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);
}
- /**
- * Temporarily pauses rotation changes until resumed.
- *
- * This can be used to prevent rotation changes from occurring while the user is
- * performing certain operations, such as drag and drop.
- *
- * This call nests and must be matched by an equal number of calls to
- * {@link #resumeRotationLocked}.
- */
- void pauseRotationLocked() {
- mDeferredRotationPauseCount += 1;
- }
-
- /**
- * Resumes normal rotation changes after being paused.
- */
- void resumeRotationLocked() {
- if (mDeferredRotationPauseCount > 0) {
- mDeferredRotationPauseCount -= 1;
- if (mDeferredRotationPauseCount == 0) {
- // TODO(multi-display): Update rotation for different displays separately.
- final DisplayContent displayContent = getDefaultDisplayContentLocked();
- final boolean changed = displayContent.updateRotationUnchecked();
- if (changed) {
- mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayContent.getDisplayId())
- .sendToTarget();
- }
- }
- }
- }
-
private void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
if(DEBUG_ORIENTATION) Slog.v(TAG_WM, "updateRotationUnchecked:"
+ " alwaysSendConfiguration=" + alwaysSendConfiguration
@@ -3907,6 +3875,15 @@
@Override
public int watchRotation(IRotationWatcher watcher, int displayId) {
+ final DisplayContent displayContent;
+ synchronized (mWindowMap) {
+ displayContent = mRoot.getDisplayContent(displayId);
+ }
+ if (displayContent == null) {
+ throw new IllegalArgumentException("Trying to register rotation event "
+ + "for invalid display: " + displayId);
+ }
+
final IBinder watcherBinder = watcher.asBinder();
IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
@Override
@@ -3934,7 +3911,7 @@
// Client died, no cleanup needed.
}
- return getDefaultDisplayRotation();
+ return displayContent.getRotation();
}
}
@@ -4719,9 +4696,9 @@
} break;
case WINDOW_FREEZE_TIMEOUT: {
- // TODO(multidisplay): Can non-default displays rotate?
+ final DisplayContent displayContent = (DisplayContent) msg.obj;
synchronized (mWindowMap) {
- getDefaultDisplayContentLocked().onWindowFreezeTimeout();
+ displayContent.onWindowFreezeTimeout();
}
break;
}
@@ -5034,11 +5011,9 @@
}
break;
case SEAMLESS_ROTATION_TIMEOUT: {
- // Rotation only supported on primary display.
- // TODO(multi-display)
- synchronized(mWindowMap) {
- final DisplayContent dc = getDefaultDisplayContentLocked();
- dc.onSeamlessRotationTimeout();
+ final DisplayContent displayContent = (DisplayContent) msg.obj;
+ synchronized (mWindowMap) {
+ displayContent.onSeamlessRotationTimeout();
}
}
break;
@@ -5078,6 +5053,12 @@
Slog.v(TAG_WM, "handleMessage: exit");
}
}
+
+ /** Remove the previous messages with the same 'what' and 'obj' then send the new one. */
+ void sendNewMessageDelayed(int what, Object obj, long delayMillis) {
+ removeMessages(what, obj);
+ sendMessageDelayed(obtainMessage(what, obj), delayMillis);
+ }
}
void destroyPreservedSurfaceLocked() {
@@ -5541,8 +5522,7 @@
mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
// XXX should probably keep timeout from
// when we first froze the display.
- mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
- mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT,
+ mH.sendNewMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, w.getDisplayContent(),
WINDOW_FREEZE_TIMEOUT_DURATION);
}
}
@@ -5789,8 +5769,7 @@
}
mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN);
- // TODO(multidisplay): rotation on non-default displays
- if (CUSTOM_SCREEN_ROTATION && displayContent.isDefaultDisplay) {
+ if (CUSTOM_SCREEN_ROTATION) {
mExitAnimId = exitAnim;
mEnterAnimId = enterAnim;
ScreenRotationAnimation screenRotationAnimation =
@@ -6475,7 +6454,6 @@
pw.print(defaultDisplayContent.getLastWindowForcedOrientation());
pw.print(" mLastOrientation=");
pw.println(defaultDisplayContent.getLastOrientation());
- pw.print(" mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
pw.print(" Animation settings: disabled="); pw.print(mAnimationsDisabled);
pw.print(" window="); pw.print(mWindowAnimationScaleSetting);
pw.print(" transition="); pw.print(mTransitionAnimationScaleSetting);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c8c4b58..fb0c3bc 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2493,8 +2493,8 @@
return getWindowConfiguration().keepVisibleDeadAppWindowOnScreen();
}
- /** @return true if this window desires key events. */
- boolean canReceiveKeys() {
+ @Override
+ public boolean canReceiveKeys() {
return isVisibleOrAdding()
&& (mViewVisibility == View.VISIBLE) && !mRemoveOnExit
&& ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 252a1fd..85de581 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -235,6 +235,8 @@
"com.android.server.timedetector.TimeDetectorService$Lifecycle";
private static final String TIME_ZONE_DETECTOR_SERVICE_CLASS =
"com.android.server.timezonedetector.TimeZoneDetectorService$Lifecycle";
+ private static final String ACCESSIBILITY_MANAGER_SERVICE_CLASS =
+ "com.android.server.accessibility.AccessibilityManagerService$Lifecycle";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
@@ -957,8 +959,7 @@
traceBeginAndSlog("StartAccessibilityManagerService");
try {
- ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
- new AccessibilityManagerService(context));
+ mSystemServiceManager.startService(ACCESSIBILITY_MANAGER_SERVICE_CLASS);
} catch (Throwable e) {
reportWtf("starting Accessibility Manager", e);
}
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
index 7487d44..044186f3 100644
--- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -255,6 +255,9 @@
}
@Override
+ public boolean canReceiveKeys() { return false; }
+
+ @Override
public void writeIdentifierToProto(ProtoOutputStream proto, long fieldId){
throw new UnsupportedOperationException("not implemented");
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index cd8e650..4e9894b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -37,6 +37,8 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -351,34 +353,36 @@
*/
@Test
public void testMaxUiWidth() throws Exception {
+ // Prevent base display metrics for test from being updated to the value of real display.
+ final DisplayContent displayContent = createDisplayNoUpdateDisplayInfo();
final int baseWidth = 1440;
final int baseHeight = 2560;
final int baseDensity = 300;
- mDisplayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
+ displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
final int maxWidth = 300;
final int resultingHeight = (maxWidth * baseHeight) / baseWidth;
final int resultingDensity = (maxWidth * baseDensity) / baseWidth;
- mDisplayContent.setMaxUiWidth(maxWidth);
- verifySizes(mDisplayContent, maxWidth, resultingHeight, resultingDensity);
+ displayContent.setMaxUiWidth(maxWidth);
+ verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
// Assert setting values again does not change;
- mDisplayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
- verifySizes(mDisplayContent, maxWidth, resultingHeight, resultingDensity);
+ displayContent.updateBaseDisplayMetrics(baseWidth, baseHeight, baseDensity);
+ verifySizes(displayContent, maxWidth, resultingHeight, resultingDensity);
final int smallerWidth = 200;
final int smallerHeight = 400;
final int smallerDensity = 100;
// Specify smaller dimension, verify that it is honored
- mDisplayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
- verifySizes(mDisplayContent, smallerWidth, smallerHeight, smallerDensity);
+ displayContent.updateBaseDisplayMetrics(smallerWidth, smallerHeight, smallerDensity);
+ verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
// Verify that setting the max width to a greater value than the base width has no effect
- mDisplayContent.setMaxUiWidth(maxWidth);
- verifySizes(mDisplayContent, smallerWidth, smallerHeight, smallerDensity);
+ displayContent.setMaxUiWidth(maxWidth);
+ verifySizes(displayContent, smallerWidth, smallerHeight, smallerDensity);
}
/**
@@ -476,22 +480,42 @@
@Test
public void testDisplayCutout_rot90() throws Exception {
synchronized (sWm.getWindowManagerLock()) {
- final DisplayContent dc = createNewDisplay();
- dc.mInitialDisplayWidth = 200;
- dc.mInitialDisplayHeight = 400;
- Rect r1 = new Rect(80, 0, 120, 10);
+ // Prevent mInitialDisplayCutout from being updated from real display (e.g. null
+ // if the device has no cutout).
+ final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
+ // Rotation may use real display info to compute bound, so here also uses the
+ // same width and height.
+ final int displayWidth = dc.mInitialDisplayWidth;
+ final int displayHeight = dc.mInitialDisplayHeight;
+ final int cutoutWidth = 40;
+ final int cutoutHeight = 10;
+ final int left = (displayWidth - cutoutWidth) / 2;
+ final int top = 0;
+ final int right = (displayWidth + cutoutWidth) / 2;
+ final int bottom = cutoutHeight;
+
+ final Rect r1 = new Rect(left, top, right, bottom);
final DisplayCutout cutout = new WmDisplayCutout(
fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom), null)
- .computeSafeInsets(200, 400).getDisplayCutout();
+ .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
dc.mInitialDisplayCutout = cutout;
dc.setRotation(Surface.ROTATION_90);
dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
- final Rect r = new Rect(0, 80, 10, 120);
+ // ----o---------- -------------
+ // | | | | |
+ // | ------o | o---
+ // | | | |
+ // | | -> | |
+ // | | ---o
+ // | | |
+ // | | -------------
+ final Rect r = new Rect(top, left, bottom, right);
assertEquals(new WmDisplayCutout(
fromBoundingRect(r.left, r.top, r.right, r.bottom), null)
- .computeSafeInsets(400, 200).getDisplayCutout(), dc.getDisplayInfo().displayCutout);
+ .computeSafeInsets(displayHeight, displayWidth)
+ .getDisplayCutout(), dc.getDisplayInfo().displayCutout);
}
}
@@ -553,6 +577,16 @@
assertEquals(displayContent.mBaseDisplayDensity, expectedBaseDensity);
}
+ /**
+ * Create DisplayContent that does not update display base/initial values from device to keep
+ * the values set by test.
+ */
+ private DisplayContent createDisplayNoUpdateDisplayInfo() {
+ final DisplayContent displayContent = spy(createNewDisplay());
+ doNothing().when(displayContent).updateDisplayInfo();
+ return displayContent;
+ }
+
private void assertForAllWindowsOrder(List<WindowState> expectedWindowsBottomToTop) {
final LinkedList<WindowState> actualWindows = new LinkedList<>();
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index a8411aa..ce9becd 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -524,9 +524,12 @@
0xFE837: (ord('0'), COMBINING_KEYCAP),
}
+# This is used to define the emoji that should have the same glyph.
+# i.e. previously we had gender based Kiss (0x1F48F), which had the same glyph
+# with Kiss: Woman, Man (0x1F469, 0x200D, 0x2764, 0x200D, 0x1F48B, 0x200D, 0x1F468)
+# in that case a valid row would be:
+# (0x1F469, 0x200D, 0x2764, 0x200D, 0x1F48B, 0x200D, 0x1F468): 0x1F48F,
ZWJ_IDENTICALS = {
- # KISS
- (0x1F469, 0x200D, 0x2764, 0x200D, 0x1F48B, 0x200D, 0x1F468): 0x1F48F,
}
SAME_FLAG_MAPPINGS = [