Merge "Revert "Revert "Revert "Revert "SharedMemory: break Cleaner reference cycle.""""" into sc-v2-dev
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 19a1d7a..45df0d9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1294,8 +1294,11 @@
}
@Override
- public void scheduleCrash(String msg, int typeId) {
- sendMessage(H.SCHEDULE_CRASH, msg, typeId);
+ public void scheduleCrash(String msg, int typeId, @Nullable Bundle extras) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = msg;
+ args.arg2 = extras;
+ sendMessage(H.SCHEDULE_CRASH, args, typeId);
}
public void dumpActivity(ParcelFileDescriptor pfd, IBinder activitytoken,
@@ -1925,11 +1928,11 @@
}
}
- private void throwRemoteServiceException(String message, int typeId) {
+ private void throwRemoteServiceException(String message, int typeId, @Nullable Bundle extras) {
// Use a switch to ensure all the type IDs are unique.
switch (typeId) {
case ForegroundServiceDidNotStartInTimeException.TYPE_ID:
- throw new ForegroundServiceDidNotStartInTimeException(message);
+ throw generateForegroundServiceDidNotStartInTimeException(message, extras);
case CannotDeliverBroadcastException.TYPE_ID:
throw new CannotDeliverBroadcastException(message);
@@ -1952,6 +1955,15 @@
}
}
+ private ForegroundServiceDidNotStartInTimeException
+ generateForegroundServiceDidNotStartInTimeException(String message, Bundle extras) {
+ final String serviceClassName =
+ ForegroundServiceDidNotStartInTimeException.getServiceClassNameFromExtras(extras);
+ final Exception inner = (serviceClassName == null) ? null
+ : Service.getStartForegroundServiceStackTrace(serviceClassName);
+ throw new ForegroundServiceDidNotStartInTimeException(message, inner);
+ }
+
class H extends Handler {
public static final int BIND_APPLICATION = 110;
@UnsupportedAppUsage
@@ -2169,9 +2181,14 @@
handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
- case SCHEDULE_CRASH:
- throwRemoteServiceException((String) msg.obj, msg.arg1);
+ case SCHEDULE_CRASH: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ String message = (String) args.arg1;
+ Bundle extras = (Bundle) args.arg2;
+ args.recycle();
+ throwRemoteServiceException(message, msg.arg1, extras);
break;
+ }
case DUMP_HEAP:
handleDumpHeap((DumpHeapData) msg.obj);
break;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index e76c139..db3c7d9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1862,6 +1862,14 @@
"Not allowed to start service " + service + ": " + cn.getClassName());
}
}
+ // If we started a foreground service in the same package, remember the stack trace.
+ if (cn != null && requireForeground) {
+ if (cn.getPackageName().equals(getOpPackageName())) {
+ Service.setStartForegroundServiceStackTrace(cn.getClassName(),
+ new StackTrace("Last startServiceCommon() call for this service was "
+ + "made here"));
+ }
+ }
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 4912703..64a9c44 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -321,6 +321,8 @@
boolean isTopActivityImmersive();
void crashApplicationWithType(int uid, int initialPid, in String packageName, int userId,
in String message, boolean force, int exceptionTypeId);
+ void crashApplicationWithTypeWithExtras(int uid, int initialPid, in String packageName,
+ int userId, in String message, boolean force, int exceptionTypeId, in Bundle extras);
/** @deprecated -- use getProviderMimeTypeAsync */
@UnsupportedAppUsage(maxTargetSdk = 29, publicAlternatives =
"Use {@link android.content.ContentResolver#getType} public API instead.")
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index d6ff6d3..448c3cf 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -107,7 +107,7 @@
void scheduleOnNewActivityOptions(IBinder token, in Bundle options);
void scheduleSuicide();
void dispatchPackageBroadcast(int cmd, in String[] packages);
- void scheduleCrash(in String msg, int typeId);
+ void scheduleCrash(in String msg, int typeId, in Bundle extras);
void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, in String path,
in ParcelFileDescriptor fd, in RemoteCallback finishCallback);
void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix,
diff --git a/core/java/android/app/RemoteServiceException.java b/core/java/android/app/RemoteServiceException.java
index 1038530..e220627 100644
--- a/core/java/android/app/RemoteServiceException.java
+++ b/core/java/android/app/RemoteServiceException.java
@@ -16,6 +16,10 @@
package android.app;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.os.Bundle;
import android.util.AndroidRuntimeException;
/**
@@ -33,6 +37,10 @@
super(msg);
}
+ public RemoteServiceException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
/**
* Exception used to crash an app process when it didn't call {@link Service#startForeground}
* in time after the service was started with
@@ -44,8 +52,21 @@
/** The type ID passed to {@link IApplicationThread#scheduleCrash}. */
public static final int TYPE_ID = 1;
- public ForegroundServiceDidNotStartInTimeException(String msg) {
- super(msg);
+ private static final String KEY_SERVICE_CLASS_NAME = "serviceclassname";
+
+ public ForegroundServiceDidNotStartInTimeException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ public static Bundle createExtrasForService(@NonNull ComponentName service) {
+ Bundle b = new Bundle();
+ b.putString(KEY_SERVICE_CLASS_NAME, service.getClassName());
+ return b;
+ }
+
+ @Nullable
+ public static String getServiceClassNameFromExtras(@Nullable Bundle extras) {
+ return (extras == null) ? null : extras.getString(KEY_SERVICE_CLASS_NAME);
}
}
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 3363872..5a5ccb5 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -33,9 +33,12 @@
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.contentcapture.ContentCaptureManager;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -733,6 +736,7 @@
mActivityManager.setServiceForeground(
new ComponentName(this, mClassName), mToken, id,
notification, 0, FOREGROUND_SERVICE_TYPE_MANIFEST);
+ clearStartForegroundServiceStackTrace();
} catch (RemoteException ex) {
}
}
@@ -786,6 +790,7 @@
mActivityManager.setServiceForeground(
new ComponentName(this, mClassName), mToken, id,
notification, 0, foregroundServiceType);
+ clearStartForegroundServiceStackTrace();
} catch (RemoteException ex) {
}
}
@@ -941,4 +946,34 @@
private IActivityManager mActivityManager = null;
@UnsupportedAppUsage
private boolean mStartCompatibility = false;
+
+ /**
+ * This keeps track of the stacktrace where Context.startForegroundService() was called
+ * for each service class. We use that when we crash the app for not calling
+ * {@link #startForeground} in time, in {@link ActivityThread#throwRemoteServiceException}.
+ */
+ @GuardedBy("sStartForegroundServiceStackTraces")
+ private static final ArrayMap<String, StackTrace> sStartForegroundServiceStackTraces =
+ new ArrayMap<>();
+
+ /** @hide */
+ public static void setStartForegroundServiceStackTrace(
+ @NonNull String className, @NonNull StackTrace stacktrace) {
+ synchronized (sStartForegroundServiceStackTraces) {
+ sStartForegroundServiceStackTraces.put(className, stacktrace);
+ }
+ }
+
+ private void clearStartForegroundServiceStackTrace() {
+ synchronized (sStartForegroundServiceStackTraces) {
+ sStartForegroundServiceStackTraces.remove(this.getClassName());
+ }
+ }
+
+ /** @hide */
+ public static StackTrace getStartForegroundServiceStackTrace(@NonNull String className) {
+ synchronized (sStartForegroundServiceStackTraces) {
+ return sStartForegroundServiceStackTraces.get(className);
+ }
+ }
}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerInternal.java b/core/java/android/app/StackTrace.java
similarity index 65%
rename from core/java/android/hardware/devicestate/DeviceStateManagerInternal.java
rename to core/java/android/app/StackTrace.java
index 4c91c16..ec058f8 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerInternal.java
+++ b/core/java/android/app/StackTrace.java
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-package android.hardware.devicestate;
+package android.app;
/**
- * Device state manager local system service interface.
- *
- * @hide Only for use within the system server.
+ * An Exception subclass that's used only for logging stacktraces.
+ * @hide
*/
-public abstract class DeviceStateManagerInternal {
-
- /** Returns the list of currently supported device state identifiers. */
- public abstract int[] getSupportedStateIdentifiers();
+public class StackTrace extends Exception {
+ public StackTrace(String message) {
+ super(message);
+ }
}
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 5bb51c1..4f20553 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -35,7 +35,6 @@
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Objects;
-import java.util.Set;
/**
* Display manager local system service interface.
@@ -130,14 +129,6 @@
public abstract DisplayInfo getDisplayInfo(int displayId);
/**
- * Returns a set of DisplayInfo, for the states that may be assumed by either the given display,
- * or any other display within that display's group.
- *
- * @param displayId The logical display id to fetch DisplayInfo for.
- */
- public abstract Set<DisplayInfo> getPossibleDisplayInfo(int displayId);
-
- /**
* Returns the position of the display's projection.
*
* @param displayId The logical display id.
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 7631269..0fc6b08 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -374,8 +374,8 @@
currentDisplayInfo = possibleDisplayInfos.get(i);
// Calculate max bounds for this rotation and state.
- Rect maxBounds = new Rect(0, 0, currentDisplayInfo.logicalWidth,
- currentDisplayInfo.logicalHeight);
+ Rect maxBounds = new Rect(0, 0, currentDisplayInfo.getNaturalWidth(),
+ currentDisplayInfo.getNaturalHeight());
// Calculate insets for the rotated max bounds.
// TODO(181127261) calculate insets for each display rotation and state.
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index df0c64c..9f48c06 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -532,7 +532,7 @@
}
@Override
- public void scheduleCrash(String s, int i) throws RemoteException {
+ public void scheduleCrash(String s, int i, Bundle extras) throws RemoteException {
}
@Override
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
deleted file mode 100644
index e2c67fd..0000000
--- a/libs/WindowManager/Shell/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# sysui owners
-hwwang@google.com
-winsonc@google.com
-madym@google.com
diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml
new file mode 100644
index 0000000..329e5b9
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/taskbar_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_500" android:lStar="35" />
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS
new file mode 100644
index 0000000..4d9b520
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-modules apppair owner
+chenghsiuchang@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS
new file mode 100644
index 0000000..8271014
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-module bubble owner
+madym@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 6b62204..9500e8a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -56,6 +56,7 @@
import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
+import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.freeform.FreeformTaskListener;
import com.android.wm.shell.fullscreen.FullscreenTaskListener;
@@ -156,8 +157,16 @@
@WMSingleton
@Provides
static DragAndDropController provideDragAndDropController(Context context,
- DisplayController displayController, UiEventLogger uiEventLogger) {
- return new DragAndDropController(context, displayController, uiEventLogger);
+ DisplayController displayController, UiEventLogger uiEventLogger,
+ IconProvider iconProvider, @ShellMainThread ShellExecutor mainExecutor) {
+ return new DragAndDropController(context, displayController, uiEventLogger, iconProvider,
+ mainExecutor);
+ }
+
+ @WMSingleton
+ @Provides
+ static DragAndDrop provideDragAndDrop(DragAndDropController dragAndDropController) {
+ return dragAndDropController.asDragAndDrop();
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java
new file mode 100644
index 0000000..edeff6e3
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.draganddrop;
+
+import android.content.res.Configuration;
+
+import com.android.wm.shell.common.annotations.ExternalThread;
+
+/**
+ * Interface for telling DragAndDrop stuff.
+ */
+@ExternalThread
+public interface DragAndDrop {
+
+ /** Called when the theme changes. */
+ void onThemeChanged();
+
+ /** Called when the configuration changes. */
+ void onConfigChanged(Configuration newConfig);
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index d2b4711..101295d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -41,7 +41,6 @@
import android.graphics.PixelFormat;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.Display;
import android.view.DragEvent;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
@@ -53,8 +52,10 @@
import com.android.internal.logging.InstanceId;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -71,16 +72,26 @@
private final Context mContext;
private final DisplayController mDisplayController;
private final DragAndDropEventLogger mLogger;
+ private final IconProvider mIconProvider;
private SplitScreenController mSplitScreen;
+ private ShellExecutor mMainExecutor;
+ private DragAndDropImpl mImpl;
private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
public DragAndDropController(Context context, DisplayController displayController,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger, IconProvider iconProvider, ShellExecutor mainExecutor) {
mContext = context;
mDisplayController = displayController;
mLogger = new DragAndDropEventLogger(uiEventLogger);
+ mIconProvider = iconProvider;
+ mMainExecutor = mainExecutor;
+ mImpl = new DragAndDropImpl();
+ }
+
+ public DragAndDrop asDragAndDrop() {
+ return mImpl;
}
public void initialize(Optional<SplitScreenController> splitscreen) {
@@ -117,7 +128,7 @@
R.layout.global_drop_target, null);
rootView.setOnDragListener(this);
rootView.setVisibility(View.INVISIBLE);
- DragLayout dragLayout = new DragLayout(context, mSplitScreen);
+ DragLayout dragLayout = new DragLayout(context, mSplitScreen, mIconProvider);
rootView.addView(dragLayout,
new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
try {
@@ -267,6 +278,18 @@
return mimeTypes;
}
+ private void onThemeChange() {
+ for (int i = 0; i < mDisplayDropTargets.size(); i++) {
+ mDisplayDropTargets.get(i).dragLayout.onThemeChange();
+ }
+ }
+
+ private void onConfigChanged(Configuration newConfig) {
+ for (int i = 0; i < mDisplayDropTargets.size(); i++) {
+ mDisplayDropTargets.get(i).dragLayout.onConfigChanged(newConfig);
+ }
+ }
+
private static class PerDisplay {
final int displayId;
final Context context;
@@ -287,4 +310,21 @@
dragLayout = dl;
}
}
+
+ private class DragAndDropImpl implements DragAndDrop {
+
+ @Override
+ public void onThemeChanged() {
+ mMainExecutor.execute(() -> {
+ DragAndDropController.this.onThemeChange();
+ });
+ }
+
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ mMainExecutor.execute(() -> {
+ DragAndDropController.this.onConfigChanged(newConfig);
+ });
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index efc9ed0..20d8054 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -16,78 +16,138 @@
package com.android.wm.shell.draganddrop;
-import static com.android.wm.shell.animation.Interpolators.FAST_OUT_LINEAR_IN;
-import static com.android.wm.shell.animation.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.wm.shell.animation.Interpolators.LINEAR;
-import static com.android.wm.shell.animation.Interpolators.LINEAR_OUT_SLOW_IN;
+import static android.app.StatusBarManager.DISABLE_NONE;
+
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.annotation.SuppressLint;
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.StatusBarManager;
import android.content.ClipData;
import android.content.Context;
-import android.graphics.Canvas;
+import android.content.res.Configuration;
+import android.graphics.Color;
import android.graphics.Insets;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
import android.view.DragEvent;
import android.view.SurfaceControl;
-import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.WindowInsets.Type;
-
-import androidx.annotation.NonNull;
+import android.widget.LinearLayout;
import com.android.internal.logging.InstanceId;
import com.android.internal.protolog.common.ProtoLog;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.util.ArrayList;
+import java.util.List;
/**
* Coordinates the visible drop targets for the current drag.
*/
-public class DragLayout extends View {
+public class DragLayout extends LinearLayout {
+
+ // While dragging the status bar is hidden.
+ private static final int HIDE_STATUS_BAR_FLAGS = StatusBarManager.DISABLE_NOTIFICATION_ICONS
+ | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
+ | StatusBarManager.DISABLE_CLOCK
+ | StatusBarManager.DISABLE_SYSTEM_INFO;
private final DragAndDropPolicy mPolicy;
+ private final SplitScreenController mSplitScreenController;
+ private final IconProvider mIconProvider;
+ private final StatusBarManager mStatusBarManager;
private DragAndDropPolicy.Target mCurrentTarget = null;
- private DropOutlineDrawable mDropOutline;
+ private DropZoneView mDropZoneView1;
+ private DropZoneView mDropZoneView2;
+
private int mDisplayMargin;
private Insets mInsets = Insets.NONE;
private boolean mIsShowing;
private boolean mHasDropped;
- public DragLayout(Context context, SplitScreenController splitscreen) {
+ @SuppressLint("WrongConstant")
+ public DragLayout(Context context, SplitScreenController splitScreenController,
+ IconProvider iconProvider) {
super(context);
- mPolicy = new DragAndDropPolicy(context, splitscreen);
+ mSplitScreenController = splitScreenController;
+ mIconProvider = iconProvider;
+ mPolicy = new DragAndDropPolicy(context, splitScreenController);
+ mStatusBarManager = context.getSystemService(StatusBarManager.class);
+
mDisplayMargin = context.getResources().getDimensionPixelSize(
R.dimen.drop_layout_display_margin);
- mDropOutline = new DropOutlineDrawable(context);
- setBackground(mDropOutline);
- setWillNotDraw(false);
+
+ mDropZoneView1 = new DropZoneView(context);
+ mDropZoneView2 = new DropZoneView(context);
+ addView(mDropZoneView1, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ addView(mDropZoneView2, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ ((LayoutParams) mDropZoneView1.getLayoutParams()).weight = 1;
+ ((LayoutParams) mDropZoneView2.getLayoutParams()).weight = 1;
+ updateContainerMargins();
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mInsets = insets.getInsets(Type.systemBars() | Type.displayCutout());
recomputeDropTargets();
+
+ final int orientation = getResources().getConfiguration().orientation;
+ if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ mDropZoneView1.setBottomInset(mInsets.bottom);
+ mDropZoneView2.setBottomInset(mInsets.bottom);
+ } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ mDropZoneView1.setBottomInset(0);
+ mDropZoneView2.setBottomInset(mInsets.bottom);
+ }
return super.onApplyWindowInsets(insets);
}
- @Override
- protected boolean verifyDrawable(@NonNull Drawable who) {
- return who == mDropOutline || super.verifyDrawable(who);
+ public void onThemeChange() {
+ mDropZoneView1.onThemeChange();
+ mDropZoneView2.onThemeChange();
}
- @Override
- protected void onDraw(Canvas canvas) {
- if (mCurrentTarget != null) {
- mDropOutline.draw(canvas);
+ public void onConfigChanged(Configuration newConfig) {
+ final int orientation = getResources().getConfiguration().orientation;
+ if (orientation == Configuration.ORIENTATION_LANDSCAPE
+ && getOrientation() != HORIZONTAL) {
+ setOrientation(LinearLayout.HORIZONTAL);
+ updateContainerMargins();
+ } else if (orientation == Configuration.ORIENTATION_PORTRAIT
+ && getOrientation() != VERTICAL) {
+ setOrientation(LinearLayout.VERTICAL);
+ updateContainerMargins();
+ }
+ }
+
+ private void updateContainerMargins() {
+ final int orientation = getResources().getConfiguration().orientation;
+ final float halfMargin = mDisplayMargin / 2f;
+ if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ mDropZoneView1.setContainerMargin(
+ mDisplayMargin, mDisplayMargin, halfMargin, mDisplayMargin);
+ mDropZoneView2.setContainerMargin(
+ halfMargin, mDisplayMargin, mDisplayMargin, mDisplayMargin);
+ } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ mDropZoneView1.setContainerMargin(
+ mDisplayMargin, mDisplayMargin, mDisplayMargin, halfMargin);
+ mDropZoneView2.setContainerMargin(
+ mDisplayMargin, halfMargin, mDisplayMargin, mDisplayMargin);
}
}
@@ -104,6 +164,43 @@
mPolicy.start(displayLayout, initialData, loggerSessionId);
mHasDropped = false;
mCurrentTarget = null;
+
+ List<ActivityManager.RunningTaskInfo> tasks = null;
+ // Figure out the splashscreen info for the existing task(s).
+ try {
+ tasks = ActivityTaskManager.getService().getTasks(2,
+ false /* filterOnlyVisibleRecents */,
+ false /* keepIntentExtra */);
+ } catch (RemoteException e) {
+ // don't show an icon / will just use the defaults
+ }
+ if (tasks != null && !tasks.isEmpty()) {
+ ActivityManager.RunningTaskInfo taskInfo1 = tasks.get(0);
+ Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
+ int bgColor1 = getResizingBackgroundColor(taskInfo1);
+
+ boolean alreadyInSplit = mSplitScreenController != null
+ && mSplitScreenController.isSplitScreenVisible();
+ if (alreadyInSplit && tasks.size() > 1) {
+ ActivityManager.RunningTaskInfo taskInfo2 = tasks.get(1);
+ Drawable icon2 = mIconProvider.getIcon(taskInfo2.topActivityInfo);
+ int bgColor2 = getResizingBackgroundColor(taskInfo2);
+
+ // figure out which task is on which side
+ int splitPosition1 = mSplitScreenController.getSplitPosition(taskInfo1.taskId);
+ boolean isTask1TopOrLeft = splitPosition1 == SPLIT_POSITION_TOP_OR_LEFT;
+ if (isTask1TopOrLeft) {
+ mDropZoneView1.setAppInfo(bgColor1, icon1);
+ mDropZoneView2.setAppInfo(bgColor2, icon2);
+ } else {
+ mDropZoneView2.setAppInfo(bgColor1, icon1);
+ mDropZoneView1.setAppInfo(bgColor2, icon2);
+ }
+ } else {
+ mDropZoneView1.setAppInfo(bgColor1, icon1);
+ mDropZoneView2.setAppInfo(bgColor1, icon1);
+ }
+ }
}
public void show() {
@@ -139,20 +236,14 @@
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
if (target == null) {
// Animating to no target
- mDropOutline.startVisibilityAnimation(false, LINEAR);
- Rect finalBounds = new Rect(mCurrentTarget.drawRegion);
- finalBounds.inset(mDisplayMargin, mDisplayMargin);
- mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN);
+ animateSplitContainers(false, null /* animCompleteCallback */);
} else if (mCurrentTarget == null) {
// Animating to first target
- mDropOutline.startVisibilityAnimation(true, LINEAR);
- Rect initialBounds = new Rect(target.drawRegion);
- initialBounds.inset(mDisplayMargin, mDisplayMargin);
- mDropOutline.setRegionBounds(initialBounds);
- mDropOutline.startBoundsAnimation(target.drawRegion, LINEAR_OUT_SLOW_IN);
+ animateSplitContainers(true, null /* animCompleteCallback */);
+ animateHighlight(target);
} else {
- // Bounds change
- mDropOutline.startBoundsAnimation(target.drawRegion, FAST_OUT_SLOW_IN);
+ // Switching between targets
+ animateHighlight(target);
}
mCurrentTarget = target;
}
@@ -163,26 +254,7 @@
*/
public void hide(DragEvent event, Runnable hideCompleteCallback) {
mIsShowing = false;
- ObjectAnimator alphaAnimator = mDropOutline.startVisibilityAnimation(false, LINEAR);
- ObjectAnimator boundsAnimator = null;
- if (mCurrentTarget != null) {
- Rect finalBounds = new Rect(mCurrentTarget.drawRegion);
- finalBounds.inset(mDisplayMargin, mDisplayMargin);
- boundsAnimator = mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN);
- }
-
- if (hideCompleteCallback != null) {
- ObjectAnimator lastAnim = boundsAnimator != null
- ? boundsAnimator
- : alphaAnimator;
- lastAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- hideCompleteCallback.run();
- }
- });
- }
-
+ animateSplitContainers(false, hideCompleteCallback);
mCurrentTarget = null;
}
@@ -201,4 +273,49 @@
hide(event, dropCompleteCallback);
return handledDrop;
}
+
+ private void animateSplitContainers(boolean visible, Runnable animCompleteCallback) {
+ mStatusBarManager.disable(visible
+ ? HIDE_STATUS_BAR_FLAGS
+ : DISABLE_NONE);
+ mDropZoneView1.setShowingMargin(visible);
+ mDropZoneView2.setShowingMargin(visible);
+ ObjectAnimator animator = mDropZoneView1.getAnimator();
+ if (animCompleteCallback != null) {
+ if (animator != null) {
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ animCompleteCallback.run();
+ }
+ });
+ } else {
+ // If there's no animator the animation is done so run immediately
+ animCompleteCallback.run();
+ }
+ }
+ }
+
+ private void animateHighlight(DragAndDropPolicy.Target target) {
+ if (target.type == DragAndDropPolicy.Target.TYPE_SPLIT_LEFT
+ || target.type == DragAndDropPolicy.Target.TYPE_SPLIT_TOP) {
+ mDropZoneView1.setShowingHighlight(true);
+ mDropZoneView1.setShowingSplash(false);
+
+ mDropZoneView2.setShowingHighlight(false);
+ mDropZoneView2.setShowingSplash(true);
+ } else if (target.type == DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT
+ || target.type == DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM) {
+ mDropZoneView1.setShowingHighlight(false);
+ mDropZoneView1.setShowingSplash(true);
+
+ mDropZoneView2.setShowingHighlight(true);
+ mDropZoneView2.setShowingSplash(false);
+ }
+ }
+
+ private static int getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
+ final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
+ return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb();
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
new file mode 100644
index 0000000..2f47af5
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.draganddrop;
+
+import static com.android.wm.shell.animation.Interpolators.FAST_OUT_SLOW_IN;
+
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Path;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.util.IntProperty;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.policy.ScreenDecorationsUtils;
+import com.android.wm.shell.R;
+
+/**
+ * Renders a drop zone area for items being dragged.
+ */
+public class DropZoneView extends FrameLayout {
+
+ private static final int SPLASHSCREEN_ALPHA_INT = (int) (255 * 0.90f);
+ private static final int HIGHLIGHT_ALPHA_INT = 255;
+ private static final int MARGIN_ANIMATION_ENTER_DURATION = 400;
+ private static final int MARGIN_ANIMATION_EXIT_DURATION = 250;
+
+ private static final FloatProperty<DropZoneView> INSETS =
+ new FloatProperty<DropZoneView>("insets") {
+ @Override
+ public void setValue(DropZoneView v, float percent) {
+ v.setMarginPercent(percent);
+ }
+
+ @Override
+ public Float get(DropZoneView v) {
+ return v.getMarginPercent();
+ }
+ };
+
+ private static final IntProperty<ColorDrawable> SPLASHSCREEN_ALPHA =
+ new IntProperty<ColorDrawable>("splashscreen") {
+ @Override
+ public void setValue(ColorDrawable d, int alpha) {
+ d.setAlpha(alpha);
+ }
+
+ @Override
+ public Integer get(ColorDrawable d) {
+ return d.getAlpha();
+ }
+ };
+
+ private static final IntProperty<ColorDrawable> HIGHLIGHT_ALPHA =
+ new IntProperty<ColorDrawable>("highlight") {
+ @Override
+ public void setValue(ColorDrawable d, int alpha) {
+ d.setAlpha(alpha);
+ }
+
+ @Override
+ public Integer get(ColorDrawable d) {
+ return d.getAlpha();
+ }
+ };
+
+ private final Path mPath = new Path();
+ private final float[] mContainerMargin = new float[4];
+ private float mCornerRadius;
+ private float mBottomInset;
+ private int mMarginColor; // i.e. color used for negative space like the container insets
+ private int mHighlightColor;
+
+ private boolean mShowingHighlight;
+ private boolean mShowingSplash;
+ private boolean mShowingMargin;
+
+ // TODO: might be more seamless to animate between splash/highlight color instead of 2 separate
+ private ObjectAnimator mSplashAnimator;
+ private ObjectAnimator mHighlightAnimator;
+ private ObjectAnimator mMarginAnimator;
+ private float mMarginPercent;
+
+ // Renders a highlight or neutral transparent color
+ private ColorDrawable mDropZoneDrawable;
+ // Renders the translucent splashscreen with the app icon in the middle
+ private ImageView mSplashScreenView;
+ private ColorDrawable mSplashBackgroundDrawable;
+ // Renders the margin / insets around the dropzone container
+ private MarginView mMarginView;
+
+ public DropZoneView(Context context) {
+ this(context, null);
+ }
+
+ public DropZoneView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public DropZoneView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public DropZoneView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ setContainerMargin(0, 0, 0, 0); // make sure it's populated
+
+ mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
+ mMarginColor = getResources().getColor(R.color.taskbar_background);
+ mHighlightColor = getResources().getColor(android.R.color.system_accent1_500);
+
+ mDropZoneDrawable = new ColorDrawable();
+ mDropZoneDrawable.setColor(mHighlightColor);
+ mDropZoneDrawable.setAlpha(0);
+ setBackgroundDrawable(mDropZoneDrawable);
+
+ mSplashScreenView = new ImageView(context);
+ mSplashScreenView.setScaleType(ImageView.ScaleType.CENTER);
+ mSplashBackgroundDrawable = new ColorDrawable();
+ mSplashBackgroundDrawable.setColor(Color.WHITE);
+ mSplashBackgroundDrawable.setAlpha(SPLASHSCREEN_ALPHA_INT);
+ mSplashScreenView.setBackgroundDrawable(mSplashBackgroundDrawable);
+ addView(mSplashScreenView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ mSplashScreenView.setAlpha(0f);
+
+ mMarginView = new MarginView(context);
+ addView(mMarginView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ }
+
+ public void onThemeChange() {
+ mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(getContext());
+ mMarginColor = getResources().getColor(R.color.taskbar_background);
+ mHighlightColor = getResources().getColor(android.R.color.system_accent1_500);
+
+ final int alpha = mDropZoneDrawable.getAlpha();
+ mDropZoneDrawable.setColor(mHighlightColor);
+ mDropZoneDrawable.setAlpha(alpha);
+
+ if (mMarginPercent > 0) {
+ mMarginView.invalidate();
+ }
+ }
+
+ /** Sets the desired margins around the drop zone container when fully showing. */
+ public void setContainerMargin(float left, float top, float right, float bottom) {
+ mContainerMargin[0] = left;
+ mContainerMargin[1] = top;
+ mContainerMargin[2] = right;
+ mContainerMargin[3] = bottom;
+ if (mMarginPercent > 0) {
+ mMarginView.invalidate();
+ }
+ }
+
+ /** Sets the bottom inset so the drop zones are above bottom navigation. */
+ public void setBottomInset(float bottom) {
+ mBottomInset = bottom;
+ ((LayoutParams) mSplashScreenView.getLayoutParams()).bottomMargin = (int) bottom;
+ if (mMarginPercent > 0) {
+ mMarginView.invalidate();
+ }
+ }
+
+ /** Sets the color and icon to use for the splashscreen when shown. */
+ public void setAppInfo(int splashScreenColor, Drawable appIcon) {
+ mSplashBackgroundDrawable.setColor(splashScreenColor);
+ mSplashScreenView.setImageDrawable(appIcon);
+ }
+
+ /** @return an active animator for this view if one exists. */
+ @Nullable
+ public ObjectAnimator getAnimator() {
+ if (mMarginAnimator != null && mMarginAnimator.isRunning()) {
+ return mMarginAnimator;
+ } else if (mHighlightAnimator != null && mHighlightAnimator.isRunning()) {
+ return mHighlightAnimator;
+ } else if (mSplashAnimator != null && mSplashAnimator.isRunning()) {
+ return mSplashAnimator;
+ }
+ return null;
+ }
+
+ /** Animates the splashscreen to show or hide. */
+ public void setShowingSplash(boolean showingSplash) {
+ if (mShowingSplash != showingSplash) {
+ mShowingSplash = showingSplash;
+ animateSplashToState();
+ }
+ }
+
+ /** Animates the highlight indicating the zone is hovered on or not. */
+ public void setShowingHighlight(boolean showingHighlight) {
+ if (mShowingHighlight != showingHighlight) {
+ mShowingHighlight = showingHighlight;
+ animateHighlightToState();
+ }
+ }
+
+ /** Animates the margins around the drop zone to show or hide. */
+ public void setShowingMargin(boolean visible) {
+ if (mShowingMargin != visible) {
+ mShowingMargin = visible;
+ animateMarginToState();
+ }
+ if (!mShowingMargin) {
+ setShowingHighlight(false);
+ setShowingSplash(false);
+ }
+ }
+
+ private void animateSplashToState() {
+ if (mSplashAnimator != null) {
+ mSplashAnimator.cancel();
+ }
+ mSplashAnimator = ObjectAnimator.ofInt(mSplashBackgroundDrawable,
+ SPLASHSCREEN_ALPHA,
+ mSplashBackgroundDrawable.getAlpha(),
+ mShowingSplash ? SPLASHSCREEN_ALPHA_INT : 0);
+ if (!mShowingSplash) {
+ mSplashAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+ }
+ mSplashAnimator.start();
+ mSplashScreenView.animate().alpha(mShowingSplash ? 1f : 0f).start();
+ }
+
+ private void animateHighlightToState() {
+ if (mHighlightAnimator != null) {
+ mHighlightAnimator.cancel();
+ }
+ mHighlightAnimator = ObjectAnimator.ofInt(mDropZoneDrawable,
+ HIGHLIGHT_ALPHA,
+ mDropZoneDrawable.getAlpha(),
+ mShowingHighlight ? HIGHLIGHT_ALPHA_INT : 0);
+ if (!mShowingHighlight) {
+ mHighlightAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+ }
+ mHighlightAnimator.start();
+ }
+
+ private void animateMarginToState() {
+ if (mMarginAnimator != null) {
+ mMarginAnimator.cancel();
+ }
+ mMarginAnimator = ObjectAnimator.ofFloat(this, INSETS,
+ mMarginPercent,
+ mShowingMargin ? 1f : 0f);
+ mMarginAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+ mMarginAnimator.setDuration(mShowingMargin
+ ? MARGIN_ANIMATION_ENTER_DURATION
+ : MARGIN_ANIMATION_EXIT_DURATION);
+ mMarginAnimator.start();
+ }
+
+ private void setMarginPercent(float percent) {
+ if (percent != mMarginPercent) {
+ mMarginPercent = percent;
+ mMarginView.invalidate();
+ }
+ }
+
+ private float getMarginPercent() {
+ return mMarginPercent;
+ }
+
+ /** Simple view that draws a rounded rect margin around its contents. **/
+ private class MarginView extends View {
+
+ MarginView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ mPath.reset();
+ mPath.addRoundRect(mContainerMargin[0] * mMarginPercent,
+ mContainerMargin[1] * mMarginPercent,
+ getWidth() - (mContainerMargin[2] * mMarginPercent),
+ getHeight() - (mContainerMargin[3] * mMarginPercent) - mBottomInset,
+ mCornerRadius * mMarginPercent,
+ mCornerRadius * mMarginPercent,
+ Path.Direction.CW);
+ mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD);
+ canvas.clipPath(mPath);
+ canvas.drawColor(mMarginColor);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OWNERS
new file mode 100644
index 0000000..41177f0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-module one handed mode owner
+lbill@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS
new file mode 100644
index 0000000..afddfab
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-module pip owner
+hwwang@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OWNERS
new file mode 100644
index 0000000..7237d2b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-modules splitscreen owner
+chenghsiuchang@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 262a9a1..d2e341d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -188,6 +188,10 @@
&& mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED;
}
+ public @SplitPosition int getSplitPosition(int taskId) {
+ return mStageCoordinator.getSplitPosition(taskId);
+ }
+
public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) {
return moveToStage(taskId, STAGE_TYPE_SIDE, sideStagePosition,
new WindowContainerTransaction());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index a5579ae..8ad0f20 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -678,6 +678,16 @@
outBottomOrRightBounds.set(mSplitLayout.getBounds2());
}
+ @SplitPosition
+ int getSplitPosition(int taskId) {
+ if (mSideStage.getTopVisibleChildTaskId() == taskId) {
+ return getSideStagePosition();
+ } else if (mMainStage.getTopVisibleChildTaskId() == taskId) {
+ return getMainStagePosition();
+ }
+ return SPLIT_POSITION_UNDEFINED;
+ }
+
private void addActivityOptions(Bundle opts, StageTaskListener stage) {
opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OWNERS
new file mode 100644
index 0000000..264e88f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-modules stagesplit owner
+chenghsiuchang@google.com
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
index bfa2c92..9f74520 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
@@ -30,7 +30,9 @@
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
+import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.ShellExecutor;
import org.junit.Before;
import org.junit.Test;
@@ -59,8 +61,8 @@
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
-
- mController = new DragAndDropController(mContext, mDisplayController, mUiEventLogger);
+ mController = new DragAndDropController(mContext, mDisplayController, mUiEventLogger,
+ mock(IconProvider.class), mock(ShellExecutor.class));
}
@Test
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 9cd7083..c30c742 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -98,6 +98,10 @@
private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config";
private static final String KEY_DEVICE_SPECIFIC_CONFIG = "device_specific_config";
private static final String KEY_SIM_SPECIFIC_SETTINGS = "sim_specific_settings";
+ // Restoring sim-specific data backed up from newer Android version to Android 12 was causing a
+ // fatal crash. Creating a backup with a different key will prevent Android 12 versions from
+ // restoring this data.
+ private static final String KEY_SIM_SPECIFIC_SETTINGS_2 = "sim_specific_settings_2";
// Versioning of the state file. Increment this version
// number any time the set of state items is altered.
@@ -253,7 +257,7 @@
deviceSpecificInformation, data);
stateChecksums[STATE_SIM_SPECIFIC_SETTINGS] =
writeIfChanged(stateChecksums[STATE_SIM_SPECIFIC_SETTINGS],
- KEY_SIM_SPECIFIC_SETTINGS, simSpecificSettingsData, data);
+ KEY_SIM_SPECIFIC_SETTINGS_2, simSpecificSettingsData, data);
writeNewChecksums(stateChecksums, newState);
}
@@ -395,6 +399,9 @@
break;
case KEY_SIM_SPECIFIC_SETTINGS:
+ // Intentional fall through so that sim-specific backups from Android 12 will
+ // also be restored on newer Android versions.
+ case KEY_SIM_SPECIFIC_SETTINGS_2:
byte[] restoredSimSpecificSettings = new byte[size];
data.readEntityData(restoredSimSpecificSettings, 0, size);
restoreSimSpecificSettings(restoredSimSpecificSettings);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index b56d189..ba67716 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -144,7 +144,7 @@
private static final boolean DEBUG_FACE = Build.IS_DEBUGGABLE;
private static final boolean DEBUG_FINGERPRINT = Build.IS_DEBUGGABLE;
private static final boolean DEBUG_SPEW = false;
- private static final int FINGERPRINT_LOCKOUT_RESET_DELAY_MS = 600;
+ private static final int BIOMETRIC_LOCKOUT_RESET_DELAY_MS = 600;
private static final String ACTION_FACE_UNLOCK_STARTED
= "com.android.facelock.FACE_UNLOCK_STARTED";
@@ -201,6 +201,19 @@
private static final int BIOMETRIC_STATE_CANCELLING = 2;
/**
+ * Action indicating keyguard *can* start biometric authentiation.
+ */
+ private static final int BIOMETRIC_ACTION_START = 0;
+ /**
+ * Action indicating keyguard *can* stop biometric authentiation.
+ */
+ private static final int BIOMETRIC_ACTION_STOP = 1;
+ /**
+ * Action indicating keyguard *can* start or stop biometric authentiation.
+ */
+ private static final int BIOMETRIC_ACTION_UPDATE = 2;
+
+ /**
* Biometric state: During cancelling we got another request to start listening, so when we
* receive the cancellation done signal, we should start listening again.
*/
@@ -339,13 +352,13 @@
private final Runnable mFpCancelNotReceived = () -> {
Log.e(TAG, "Fp cancellation not received, transitioning to STOPPED");
mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
- updateFingerprintListeningState();
+ updateFingerprintListeningState(BIOMETRIC_ACTION_STOP);
};
private final Runnable mFaceCancelNotReceived = () -> {
Log.e(TAG, "Face cancellation not received, transitioning to STOPPED");
mFaceRunningState = BIOMETRIC_STATE_STOPPED;
- updateFaceListeningState();
+ updateFaceListeningState(BIOMETRIC_ACTION_STOP);
};
private final Handler mHandler;
@@ -365,7 +378,7 @@
public void onChanged(boolean enabled, int userId) throws RemoteException {
mHandler.post(() -> {
mBiometricEnabledForUser.put(userId, enabled);
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
});
}
};
@@ -415,7 +428,6 @@
private final KeyguardListenQueue mListenModels = new KeyguardListenQueue();
private static int sCurrentUser;
- private Runnable mUpdateBiometricListeningState = this::updateBiometricListeningState;
public synchronized static void setCurrentUser(int currentUser) {
sCurrentUser = currentUser;
@@ -428,8 +440,17 @@
@Override
public void onTrustChanged(boolean enabled, int userId, int flags) {
Assert.isMainThread();
+ boolean wasTrusted = mUserHasTrust.get(userId, false);
mUserHasTrust.put(userId, enabled);
- updateBiometricListeningState();
+ // If there was no change in trusted state, make sure we are not authenticating.
+ // TrustManager sends an onTrustChanged whenever a user unlocks keyguard, for
+ // this reason we need to make sure to not authenticate.
+ if (wasTrusted == enabled) {
+ updateBiometricListeningState(BIOMETRIC_ACTION_STOP);
+ } else if (!enabled) {
+ updateBiometricListeningState(BIOMETRIC_ACTION_START);
+ }
+
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -594,7 +615,8 @@
*/
public void setCredentialAttempted() {
mCredentialAttempted = true;
- updateBiometricListeningState();
+ // Do not update face listening state in case of false authentication attempts.
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
/**
@@ -602,7 +624,7 @@
*/
public void setKeyguardGoingAway(boolean goingAway) {
mKeyguardGoingAway = goingAway;
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
}
/**
@@ -610,7 +632,7 @@
*/
public void setKeyguardOccluded(boolean occluded) {
mKeyguardOccluded = occluded;
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
}
@@ -622,7 +644,7 @@
*/
public void requestFaceAuthOnOccludingApp(boolean request) {
mOccludingAppRequestingFace = request;
- updateFaceListeningState();
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
}
/**
@@ -633,7 +655,7 @@
*/
public void requestFingerprintAuthOnOccludingApp(boolean request) {
mOccludingAppRequestingFp = request;
- updateFingerprintListeningState();
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
/**
@@ -641,7 +663,7 @@
*/
public void onCameraLaunched() {
mSecureCameraLaunched = true;
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
}
/**
@@ -676,7 +698,7 @@
}
// Don't send cancel if authentication succeeds
mFingerprintCancelSignal = null;
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -772,7 +794,7 @@
Log.w(TAG, "Retrying fingerprint after HW unavailable, attempt " +
mHardwareFingerprintUnavailableRetryCount);
if (mFpm.isHardwareDetected()) {
- updateFingerprintListeningState();
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
} else if (mHardwareFingerprintUnavailableRetryCount < HAL_ERROR_RETRY_MAX) {
mHardwareFingerprintUnavailableRetryCount++;
mHandler.postDelayed(mRetryFingerprintAuthentication, HAL_ERROR_RETRY_TIMEOUT);
@@ -792,7 +814,7 @@
if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
&& mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
- updateFingerprintListeningState();
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
} else {
setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
}
@@ -813,7 +835,7 @@
lockedOutStateChanged |= !mFingerprintLockedOut;
mFingerprintLockedOut = true;
if (isUdfpsEnrolled()) {
- updateFingerprintListeningState();
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
}
@@ -840,10 +862,11 @@
// that the events will arrive in a particular order. Add a delay here in case
// an unlock is in progress. In this is a normal unlock the extra delay won't
// be noticeable.
- mHandler.postDelayed(this::updateFingerprintListeningState,
- FINGERPRINT_LOCKOUT_RESET_DELAY_MS);
+ mHandler.postDelayed(() -> {
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
+ }, BIOMETRIC_LOCKOUT_RESET_DELAY_MS);
} else {
- updateFingerprintListeningState();
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
}
if (changed) {
@@ -887,7 +910,7 @@
}
// Don't send cancel if authentication succeeds
mFaceCancelSignal = null;
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -980,7 +1003,7 @@
public void run() {
Log.w(TAG, "Retrying face after HW unavailable, attempt " +
mHardwareFaceUnavailableRetryCount);
- updateFaceListeningState();
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
}
};
@@ -997,7 +1020,7 @@
if (msgId == FaceManager.FACE_ERROR_CANCELED
&& mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
setFaceRunningState(BIOMETRIC_STATE_STOPPED);
- updateFaceListeningState();
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
} else {
setFaceRunningState(BIOMETRIC_STATE_STOPPED);
}
@@ -1035,7 +1058,9 @@
boolean changed = mFaceLockedOutPermanent;
mFaceLockedOutPermanent = false;
- updateFaceListeningState();
+ mHandler.postDelayed(() -> {
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+ }, BIOMETRIC_LOCKOUT_RESET_DELAY_MS);
if (changed) {
notifyLockedOutStateChanged(BiometricSourceType.FACE);
@@ -1288,7 +1313,7 @@
@VisibleForTesting
void setAssistantVisible(boolean assistantVisible) {
mAssistantVisible = assistantVisible;
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
}
static class DisplayClientState {
@@ -1627,7 +1652,7 @@
protected void handleStartedWakingUp() {
Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp");
Assert.isMainThread();
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
@@ -1648,7 +1673,7 @@
}
}
mGoingToSleep = true;
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
}
protected void handleFinishedGoingToSleep(int arg1) {
@@ -1660,7 +1685,7 @@
cb.onFinishedGoingToSleep(arg1);
}
}
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
}
private void handleScreenTurnedOn() {
@@ -1697,7 +1722,7 @@
cb.onDreamingStateChanged(mIsDreaming);
}
}
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
}
private void handleUserInfoChanged(int userId) {
@@ -1888,7 +1913,7 @@
setAssistantVisible((boolean) msg.obj);
break;
case MSG_BIOMETRIC_AUTHENTICATION_CONTINUE:
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
break;
case MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED:
updateLogoutEnabled();
@@ -2006,10 +2031,10 @@
@Override
public void onEnrollmentsChanged() {
- mainExecutor.execute(() -> updateBiometricListeningState());
+ mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE));
}
});
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
if (mFpm != null) {
mFpm.addLockoutResetCallback(mFingerprintLockoutResetCallback);
}
@@ -2123,12 +2148,12 @@
mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED);
}
- private void updateBiometricListeningState() {
- updateFingerprintListeningState();
- updateFaceListeningState();
+ private void updateBiometricListeningState(int action) {
+ updateFingerprintListeningState(action);
+ updateFaceListeningState(action);
}
- private void updateFingerprintListeningState() {
+ private void updateFingerprintListeningState(int action) {
// If this message exists, we should not authenticate again until this message is
// consumed by the handler
if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
@@ -2140,8 +2165,16 @@
final boolean runningOrRestarting = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING
|| mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING;
if (runningOrRestarting && !shouldListenForFingerprint) {
+ if (action == BIOMETRIC_ACTION_START) {
+ Log.v(TAG, "Ignoring stopListeningForFingerprint()");
+ return;
+ }
stopListeningForFingerprint();
} else if (!runningOrRestarting && shouldListenForFingerprint) {
+ if (action == BIOMETRIC_ACTION_STOP) {
+ Log.v(TAG, "Ignoring startListeningForFingerprint()");
+ return;
+ }
startListeningForFingerprint();
}
}
@@ -2170,7 +2203,7 @@
return;
}
mAuthInterruptActive = active;
- updateFaceListeningState();
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
}
/**
@@ -2181,7 +2214,7 @@
public void requestFaceAuth(boolean userInitiatedRequest) {
if (DEBUG) Log.d(TAG, "requestFaceAuth() userInitiated=" + userInitiatedRequest);
mIsFaceAuthUserRequested |= userInitiatedRequest;
- updateFaceListeningState();
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
}
public boolean isFaceAuthUserRequested() {
@@ -2195,7 +2228,7 @@
stopListeningForFace();
}
- private void updateFaceListeningState() {
+ private void updateFaceListeningState(int action) {
// If this message exists, we should not authenticate again until this message is
// consumed by the handler
if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
@@ -2204,9 +2237,17 @@
mHandler.removeCallbacks(mRetryFaceAuthentication);
boolean shouldListenForFace = shouldListenForFace();
if (mFaceRunningState == BIOMETRIC_STATE_RUNNING && !shouldListenForFace) {
+ if (action == BIOMETRIC_ACTION_START) {
+ Log.v(TAG, "Ignoring stopListeningForFace()");
+ return;
+ }
mIsFaceAuthUserRequested = false;
stopListeningForFace();
} else if (mFaceRunningState != BIOMETRIC_STATE_RUNNING && shouldListenForFace) {
+ if (action == BIOMETRIC_ACTION_STOP) {
+ Log.v(TAG, "Ignoring startListeningForFace()");
+ return;
+ }
startListeningForFace();
}
}
@@ -2414,7 +2455,7 @@
mLockIconPressed = true;
final int userId = getCurrentUser();
mUserFaceAuthenticated.put(userId, null);
- updateFaceListeningState();
+ updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
mStrongAuthTracker.onStrongAuthRequiredChanged(userId);
}
@@ -2590,7 +2631,7 @@
*/
private void handleDevicePolicyManagerStateChanged(int userId) {
Assert.isMainThread();
- updateFingerprintListeningState();
+ updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
updateSecondaryLockscreenRequirement(userId);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -2880,7 +2921,7 @@
cb.onKeyguardVisibilityChangedRaw(showing);
}
}
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
}
/** Notifies that the occluded state changed. */
@@ -2902,7 +2943,7 @@
*/
private void handleKeyguardReset() {
if (DEBUG) Log.d(TAG, "handleKeyguardReset");
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
}
@@ -2948,7 +2989,7 @@
cb.onKeyguardBouncerChanged(mBouncer);
}
}
- updateBiometricListeningState();
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
}
/**
@@ -3068,7 +3109,9 @@
public void setSwitchingUser(boolean switching) {
mSwitchingUser = switching;
// Since this comes in on a binder thread, we need to post if first
- mHandler.post(mUpdateBiometricListeningState);
+ mHandler.post(() -> {
+ updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+ });
}
private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index d37dcaf..bb0e79f 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -121,7 +121,8 @@
.setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
.setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper())
.setRecentTasks(mWMComponent.getRecentTasks())
- .setSizeCompatUI(Optional.of(mWMComponent.getSizeCompatUI()));
+ .setSizeCompatUI(Optional.of(mWMComponent.getSizeCompatUI()))
+ .setDragAndDrop(Optional.of(mWMComponent.getDragAndDrop()));
} else {
// TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
// is separating this logic into newly creating SystemUITestsFactory.
@@ -140,7 +141,8 @@
.setStartingSurface(Optional.ofNullable(null))
.setTaskSurfaceHelper(Optional.ofNullable(null))
.setRecentTasks(Optional.ofNullable(null))
- .setSizeCompatUI(Optional.ofNullable(null));
+ .setSizeCompatUI(Optional.ofNullable(null))
+ .setDragAndDrop(Optional.ofNullable(null));
}
mSysUIComponent = builder.build();
if (mInitializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 5fdf026..c5d3a70 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -32,6 +32,7 @@
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
+import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
@@ -111,6 +112,9 @@
@BindsInstance
Builder setSizeCompatUI(Optional<SizeCompatUI> s);
+ @BindsInstance
+ Builder setDragAndDrop(Optional<DragAndDrop> d);
+
SysUIComponent build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 543ba8f..90a3ad2 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -29,6 +29,7 @@
import com.android.wm.shell.dagger.WMShellModule;
import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
+import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
@@ -119,4 +120,7 @@
@WMSingleton
SizeCompatUI getSizeCompatUI();
+
+ @WMSingleton
+ DragAndDrop getDragAndDrop();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index d27b5fc..aeef8cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -927,7 +927,9 @@
int burnInYOffset = getBurnInOffset(mBurnInYOffset * 2, false /* xAxis */)
- mBurnInYOffset;
mIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
- mAmbientIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
+ if (mAmbientIndicationArea != null) {
+ mAmbientIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
+ }
}
public void setAntiBurnInOffsetX(int burnInXOffset) {
@@ -936,7 +938,9 @@
}
mBurnInXOffset = burnInXOffset;
mIndicationArea.setTranslationX(burnInXOffset);
- mAmbientIndicationArea.setTranslationX(burnInXOffset);
+ if (mAmbientIndicationArea != null) {
+ mAmbientIndicationArea.setTranslationX(burnInXOffset);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index a56c177..b546edf 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -56,6 +56,7 @@
import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.tracing.nano.SystemUiTraceProto;
import com.android.wm.shell.ShellCommandHandler;
+import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.nano.WmShellTraceProto;
@@ -114,6 +115,7 @@
private final Optional<HideDisplayCutout> mHideDisplayCutoutOptional;
private final Optional<ShellCommandHandler> mShellCommandHandler;
private final Optional<SizeCompatUI> mSizeCompatUIOptional;
+ private final Optional<DragAndDrop> mDragAndDropOptional;
private final CommandQueue mCommandQueue;
private final ConfigurationController mConfigurationController;
@@ -142,6 +144,7 @@
Optional<HideDisplayCutout> hideDisplayCutoutOptional,
Optional<ShellCommandHandler> shellCommandHandler,
Optional<SizeCompatUI> sizeCompatUIOptional,
+ Optional<DragAndDrop> dragAndDropOptional,
CommandQueue commandQueue,
ConfigurationController configurationController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -167,6 +170,7 @@
mProtoTracer = protoTracer;
mShellCommandHandler = shellCommandHandler;
mSizeCompatUIOptional = sizeCompatUIOptional;
+ mDragAndDropOptional = dragAndDropOptional;
mSysUiMainExecutor = sysUiMainExecutor;
}
@@ -182,6 +186,7 @@
mOneHandedOptional.ifPresent(this::initOneHanded);
mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout);
mSizeCompatUIOptional.ifPresent(this::initSizeCompatUi);
+ mDragAndDropOptional.ifPresent(this::initDragAndDrop);
}
@VisibleForTesting
@@ -396,6 +401,20 @@
mKeyguardUpdateMonitor.registerCallback(mSizeCompatUIKeyguardCallback);
}
+ void initDragAndDrop(DragAndDrop dragAndDrop) {
+ mConfigurationController.addCallback(new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ dragAndDrop.onConfigChanged(newConfig);
+ }
+
+ @Override
+ public void onThemeChanged() {
+ dragAndDrop.onThemeChanged();
+ }
+ });
+ }
+
@Override
public void writeToProto(SystemUiTraceProto proto) {
if (proto.wmShell == null) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index de8cc89..ef9b850 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -1056,6 +1056,16 @@
verify(callback, atLeastOnce()).onRequireUnlockForNfc();
}
+ @Test
+ public void testFaceDoesNotAuth_afterPinAttempt() {
+ mTestableLooper.processAllMessages();
+ mKeyguardUpdateMonitor.setCredentialAttempted();
+ verify(mFingerprintManager, never()).authenticate(any(), any(), any(),
+ any(), anyInt());
+ verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+ anyBoolean());
+ }
+
private void setKeyguardBouncerVisibility(boolean isVisible) {
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isVisible);
mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index ae7afce..1e15d2a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -35,6 +35,7 @@
import com.android.systemui.tracing.ProtoTracer;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.draganddrop.DragAndDrop;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
@@ -79,6 +80,7 @@
@Mock ShellCommandHandler mShellCommandHandler;
@Mock SizeCompatUI mSizeCompatUI;
@Mock ShellExecutor mSysUiMainExecutor;
+ @Mock DragAndDrop mDragAndDrop;
@Before
public void setUp() {
@@ -87,6 +89,7 @@
mWMShell = new WMShell(mContext, Optional.of(mPip), Optional.of(mLegacySplitScreen),
Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mHideDisplayCutout),
Optional.of(mShellCommandHandler), Optional.of(mSizeCompatUI),
+ Optional.of(mDragAndDrop),
mCommandQueue, mConfigurationController, mKeyguardUpdateMonitor,
mNavigationModeController, mScreenLifecycle, mSysUiState, mProtoTracer,
mWakefulnessLifecycle, mSysUiMainExecutor);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index df2ae98..9a371f3 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -157,6 +157,7 @@
import com.android.internal.app.procstats.ServiceState;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.os.SomeArgs;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
@@ -4209,9 +4210,12 @@
if (r.app != null) {
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
- msg.obj = r.app;
- msg.getData().putCharSequence(
- ActivityManagerService.SERVICE_RECORD_KEY, r.toString());
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = r.app;
+ args.arg2 = r.toString();
+ args.arg3 = r.getComponentName();
+
+ msg.obj = args;
mAm.mHandler.sendMessage(msg);
}
}
@@ -5272,11 +5276,14 @@
}
}
- void serviceForegroundCrash(ProcessRecord app, CharSequence serviceRecord) {
- mAm.crashApplicationWithType(app.uid, app.getPid(), app.info.packageName, app.userId,
+ void serviceForegroundCrash(ProcessRecord app, String serviceRecord,
+ ComponentName service) {
+ mAm.crashApplicationWithTypeWithExtras(
+ app.uid, app.getPid(), app.info.packageName, app.userId,
"Context.startForegroundService() did not then call Service.startForeground(): "
+ serviceRecord, false /*force*/,
- ForegroundServiceDidNotStartInTimeException.TYPE_ID);
+ ForegroundServiceDidNotStartInTimeException.TYPE_ID,
+ ForegroundServiceDidNotStartInTimeException.createExtrasForService(service));
}
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index dde1ed9..53b1608 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -338,6 +338,7 @@
import com.android.internal.os.ByteTransferPipe;
import com.android.internal.os.IResultReceiver;
import com.android.internal.os.ProcessCpuTracker;
+import com.android.internal.os.SomeArgs;
import com.android.internal.os.TransferPipe;
import com.android.internal.os.Zygote;
import com.android.internal.policy.AttributeCache;
@@ -1472,8 +1473,6 @@
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
- static final String SERVICE_RECORD_KEY = "servicerecord";
-
/**
* Flag whether the current user is a "monkey", i.e. whether
* the UI is driven by a UI automation tool.
@@ -1652,8 +1651,12 @@
mServices.serviceForegroundTimeout((ServiceRecord) msg.obj);
} break;
case SERVICE_FOREGROUND_CRASH_MSG: {
- mServices.serviceForegroundCrash((ProcessRecord) msg.obj,
- msg.getData().getCharSequence(SERVICE_RECORD_KEY));
+ SomeArgs args = (SomeArgs) msg.obj;
+ mServices.serviceForegroundCrash(
+ (ProcessRecord) args.arg1,
+ (String) args.arg2,
+ (ComponentName) args.arg3);
+ args.recycle();
} break;
case UPDATE_TIME_ZONE: {
synchronized (mProcLock) {
@@ -3001,6 +3004,14 @@
@Override
public void crashApplicationWithType(int uid, int initialPid, String packageName, int userId,
String message, boolean force, int exceptionTypeId) {
+ crashApplicationWithTypeWithExtras(uid, initialPid, packageName, userId, message,
+ force, exceptionTypeId, null);
+ }
+
+ @Override
+ public void crashApplicationWithTypeWithExtras(int uid, int initialPid, String packageName,
+ int userId, String message, boolean force, int exceptionTypeId,
+ @Nullable Bundle extras) {
if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: crashApplication() from pid="
@@ -3013,7 +3024,7 @@
synchronized(this) {
mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId,
- message, force, exceptionTypeId);
+ message, force, exceptionTypeId, extras);
}
}
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index bcb42bb..0bf0fe2 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -27,6 +27,7 @@
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AnrController;
@@ -40,6 +41,7 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
+import android.os.Bundle;
import android.os.Message;
import android.os.Process;
import android.os.SystemClock;
@@ -489,7 +491,7 @@
* @param message
*/
void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId,
- String message, boolean force, int exceptionTypeId) {
+ String message, boolean force, int exceptionTypeId, @Nullable Bundle extras) {
ProcessRecord proc = null;
// Figure out which process to kill. We don't trust that initialPid
@@ -521,7 +523,7 @@
return;
}
- proc.scheduleCrashLocked(message, exceptionTypeId);
+ proc.scheduleCrashLocked(message, exceptionTypeId, extras);
if (force) {
// If the app is responsive, the scheduled crash will happen as expected
// and then the delayed summary kill will be a no-op.
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 487101b..2da4107 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -611,7 +611,7 @@
Slog.w(TAG, "Can't deliver broadcast to " + app.processName
+ " (pid " + app.getPid() + "). Crashing it.");
app.scheduleCrashLocked("can't deliver broadcast",
- CannotDeliverBroadcastException.TYPE_ID);
+ CannotDeliverBroadcastException.TYPE_ID, /* extras=*/ null);
}
throw ex;
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 14ba716..b9d7917 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -31,6 +31,7 @@
import android.content.pm.VersionedPackage;
import android.content.res.CompatibilityInfo;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -958,7 +959,7 @@
* of its subclasses.
*/
@GuardedBy("mService")
- void scheduleCrashLocked(String message, int exceptionTypeId) {
+ void scheduleCrashLocked(String message, int exceptionTypeId, @Nullable Bundle extras) {
// Checking killedbyAm should keep it from showing the crash dialog if the process
// was already dead for a good / normal reason.
if (!mKilledByAm) {
@@ -969,7 +970,7 @@
}
final long ident = Binder.clearCallingIdentity();
try {
- mThread.scheduleCrash(message, exceptionTypeId);
+ mThread.scheduleCrash(message, exceptionTypeId, extras);
} catch (RemoteException e) {
// If it's already dead our work is done. If it's wedged just kill it.
// We won't get the crash dialog or the error reporting.
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index 792feea..806a5dd 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -31,7 +31,6 @@
import android.content.Context;
import android.hardware.devicestate.DeviceStateInfo;
import android.hardware.devicestate.DeviceStateManager;
-import android.hardware.devicestate.DeviceStateManagerInternal;
import android.hardware.devicestate.IDeviceStateManager;
import android.hardware.devicestate.IDeviceStateManagerCallback;
import android.os.Binder;
@@ -162,7 +161,6 @@
@Override
public void onStart() {
publishBinderService(Context.DEVICE_STATE_SERVICE, mBinderService);
- publishLocalService(DeviceStateManagerInternal.class, new LocalService());
}
@VisibleForTesting
@@ -242,6 +240,13 @@
}
/** Returns the list of currently supported device state identifiers. */
+ private int[] getSupportedStateIdentifiers() {
+ synchronized (mLock) {
+ return getSupportedStateIdentifiersLocked();
+ }
+ }
+
+ /** Returns the list of currently supported device state identifiers. */
private int[] getSupportedStateIdentifiersLocked() {
int[] supportedStates = new int[mDeviceStates.size()];
for (int i = 0; i < supportedStates.length; i++) {
@@ -843,14 +848,4 @@
}
}
}
-
- /** Implementation of {@link DeviceStateManagerInternal} published as a local service. */
- private final class LocalService extends DeviceStateManagerInternal {
- @Override
- public int[] getSupportedStateIdentifiers() {
- synchronized (mLock) {
- return getSupportedStateIdentifiersLocked();
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index fadaf10..539e0c0 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -53,7 +53,6 @@
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.devicestate.DeviceStateManager;
-import android.hardware.devicestate.DeviceStateManagerInternal;
import android.hardware.display.AmbientBrightnessDayStats;
import android.hardware.display.BrightnessChangeEvent;
import android.hardware.display.BrightnessConfiguration;
@@ -132,7 +131,6 @@
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
-import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
@@ -212,7 +210,6 @@
private WindowManagerInternal mWindowManagerInternal;
private InputManagerInternal mInputManagerInternal;
private IMediaProjectionManager mProjectionService;
- private DeviceStateManagerInternal mDeviceStateManager;
private int[] mUserDisabledHdrTypes = {};
private boolean mAreUserDisabledHdrTypesAllowed = true;
@@ -560,9 +557,10 @@
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
- mDeviceStateManager = LocalServices.getService(DeviceStateManagerInternal.class);
- mContext.getSystemService(DeviceStateManager.class).registerCallback(
- new HandlerExecutor(mHandler), new DeviceStateListener());
+ DeviceStateManager deviceStateManager =
+ mContext.getSystemService(DeviceStateManager.class);
+ deviceStateManager.registerCallback(new HandlerExecutor(mHandler),
+ new DeviceStateListener());
scheduleTraversalLocked(false);
}
@@ -3292,53 +3290,6 @@
}
@Override
- public Set<DisplayInfo> getPossibleDisplayInfo(int displayId) {
- synchronized (mSyncRoot) {
- // Retrieve the group associated with this display id.
- final int displayGroupId =
- mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(displayId);
- if (displayGroupId == Display.INVALID_DISPLAY_GROUP) {
- Slog.w(TAG,
- "Can't get possible display info since display group for " + displayId
- + " does not exist");
- return new ArraySet<>();
- }
-
- // Assume any display in this group can be swapped out for the given display id.
- Set<DisplayInfo> possibleInfo = new ArraySet<>();
- final DisplayGroup group = mLogicalDisplayMapper.getDisplayGroupLocked(
- displayGroupId);
- for (int i = 0; i < group.getSizeLocked(); i++) {
- final int id = group.getIdLocked(i);
- final LogicalDisplay logical = mLogicalDisplayMapper.getDisplayLocked(id);
- if (logical == null) {
- Slog.w(TAG,
- "Can't get possible display info since logical display for "
- + "display id " + id + " does not exist, as part of group "
- + displayGroupId);
- } else {
- possibleInfo.add(logical.getDisplayInfoLocked());
- }
- }
-
- // For the supported device states, retrieve the DisplayInfos for the logical
- // display layout.
- if (mDeviceStateManager == null) {
- Slog.w(TAG, "Can't get supported states since DeviceStateManager not ready");
- } else {
- final int[] supportedStates =
- mDeviceStateManager.getSupportedStateIdentifiers();
- for (int state : supportedStates) {
- possibleInfo.addAll(
- mLogicalDisplayMapper.getDisplayInfoForStateLocked(state, displayId,
- displayGroupId));
- }
- }
- return possibleInfo;
- }
- }
-
- @Override
public Point getDisplayPosition(int displayId) {
synchronized (mSyncRoot) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 0fbc3e8..f0093bd 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -26,7 +26,6 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.TextUtils;
-import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.SparseArray;
@@ -41,7 +40,6 @@
import java.io.PrintWriter;
import java.util.Arrays;
-import java.util.Set;
import java.util.function.Consumer;
/**
@@ -267,61 +265,6 @@
return mDisplayGroups.get(groupId);
}
- /**
- * Returns the set of {@link DisplayInfo} for this device state, only fetching the info that is
- * part of the same display group as the provided display id. The DisplayInfo represent the
- * logical display layouts possible for the given device state.
- *
- * @param deviceState the state to query possible layouts for
- * @param displayId the display id to apply to all displays within the group
- * @param groupId the display group to filter display info for. Must be the same group as
- * the display with the provided display id.
- */
- public Set<DisplayInfo> getDisplayInfoForStateLocked(int deviceState, int displayId,
- int groupId) {
- Set<DisplayInfo> displayInfos = new ArraySet<>();
- final Layout layout = mDeviceStateToLayoutMap.get(deviceState);
- final int layoutSize = layout.size();
- for (int i = 0; i < layoutSize; i++) {
- Layout.Display displayLayout = layout.getAt(i);
- if (displayLayout == null) {
- continue;
- }
-
- // If the underlying display-device we want to use for this display
- // doesn't exist, then skip it. This can happen at startup as display-devices
- // trickle in one at a time. When the new display finally shows up, the layout is
- // recalculated so that the display is properly added to the current layout.
- final DisplayAddress address = displayLayout.getAddress();
- final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(address);
- if (device == null) {
- Slog.w(TAG, "The display device (" + address + "), is not available"
- + " for the display state " + deviceState);
- continue;
- }
-
- // Find or create the LogicalDisplay to map the DisplayDevice to.
- final int logicalDisplayId = displayLayout.getLogicalDisplayId();
- final LogicalDisplay logicalDisplay = getDisplayLocked(logicalDisplayId);
- if (logicalDisplay == null) {
- Slog.w(TAG, "The logical display (" + address + "), is not available"
- + " for the display state " + deviceState);
- continue;
- }
- final DisplayInfo temp = logicalDisplay.getDisplayInfoLocked();
- DisplayInfo displayInfo = new DisplayInfo(temp);
- if (displayInfo.displayGroupId != groupId) {
- // Ignore any displays not in the provided group.
- continue;
- }
- // A display in the same group can be swapped out at any point, so set the display id
- // for all results to the provided display id.
- displayInfo.displayId = displayId;
- displayInfos.add(displayInfo);
- }
- return displayInfos;
- }
-
public void dumpLocked(PrintWriter pw) {
pw.println("LogicalDisplayMapper:");
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
diff --git a/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java b/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
deleted file mode 100644
index ef8dee4..0000000
--- a/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_270;
-
-import android.hardware.display.DisplayManagerInternal;
-import android.util.ArraySet;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.view.DisplayInfo;
-import android.view.Surface;
-
-import java.util.Set;
-
-/**
- * Maintains a map of possible {@link DisplayInfo} for displays and states that may be encountered
- * on a device. This is not guaranteed to include all possible device states for all displays.
- *
- * By 'possible', this class only handles device states for displays and display groups it is
- * currently aware of. It can not handle all eventual states the system may enter, for example, if
- * an external display is added, or a new display is added to the group.
- */
-public class PossibleDisplayInfoMapper {
- private static final String TAG = "PossibleDisplayInfoMapper";
- private static final boolean DEBUG = false;
-
- private final DisplayManagerInternal mDisplayManagerInternal;
-
- /**
- * Map of all logical displays, indexed by logical display id.
- * Each logical display has multiple entries, one for each possible rotation and device
- * state.
- *
- * Emptied and re-calculated when a display is added, removed, or changed.
- */
- private final SparseArray<Set<DisplayInfo>> mDisplayInfos = new SparseArray<>();
-
- PossibleDisplayInfoMapper(DisplayManagerInternal displayManagerInternal) {
- mDisplayManagerInternal = displayManagerInternal;
- }
-
-
- /**
- * Returns, for the given displayId, a set of display infos. Set contains the possible rotations
- * for each supported device state.
- */
- public Set<DisplayInfo> getPossibleDisplayInfos(int displayId) {
- // Update display infos before returning, since any cached values would have been removed
- // in response to any display event. This model avoids re-computing the cache for every
- // display change event (which occurs extremely frequently in the normal usage of the
- // device).
- updatePossibleDisplayInfos(displayId);
- if (!mDisplayInfos.contains(displayId)) {
- return new ArraySet<>();
- }
- return Set.copyOf(mDisplayInfos.get(displayId));
- }
-
- /**
- * Updates the possible {@link DisplayInfo}s for the given display, by calculating the
- * DisplayInfo for each rotation across supported device states.
- */
- public void updatePossibleDisplayInfos(int displayId) {
- Set<DisplayInfo> displayInfos = mDisplayManagerInternal.getPossibleDisplayInfo(displayId);
- if (DEBUG) {
- Slog.v(TAG, "updatePossibleDisplayInfos, calculate rotations for given DisplayInfo "
- + displayInfos.size() + " on display " + displayId);
- }
- updateDisplayInfos(displayInfos);
- }
-
- /**
- * For the given displayId, removes all possible {@link DisplayInfo}.
- */
- public void removePossibleDisplayInfos(int displayId) {
- if (DEBUG && mDisplayInfos.get(displayId) != null) {
- Slog.v(TAG, "onDisplayRemoved, remove all DisplayInfo (" + mDisplayInfos.get(
- displayId).size() + ") with id " + displayId);
- }
- mDisplayInfos.remove(displayId);
- }
-
- private void updateDisplayInfos(Set<DisplayInfo> displayInfos) {
- // Empty out cache before re-computing.
- mDisplayInfos.clear();
- DisplayInfo[] originalDisplayInfos = new DisplayInfo[displayInfos.size()];
- displayInfos.toArray(originalDisplayInfos);
- // Iterate over each logical display layout for the current state.
- Set<DisplayInfo> rotatedDisplayInfos;
- for (DisplayInfo di : originalDisplayInfos) {
- rotatedDisplayInfos = new ArraySet<>();
- // Calculate all possible rotations for each logical display.
- for (int rotation = ROTATION_0; rotation <= ROTATION_270; rotation++) {
- rotatedDisplayInfos.add(applyRotation(di, rotation));
- }
- // Combine all results under the logical display id.
- Set<DisplayInfo> priorDisplayInfos = mDisplayInfos.get(di.displayId, new ArraySet<>());
- priorDisplayInfos.addAll(rotatedDisplayInfos);
- mDisplayInfos.put(di.displayId, priorDisplayInfos);
- }
- }
-
- private static DisplayInfo applyRotation(DisplayInfo displayInfo,
- @Surface.Rotation int rotation) {
- DisplayInfo updatedDisplayInfo = new DisplayInfo();
- updatedDisplayInfo.copyFrom(displayInfo);
- updatedDisplayInfo.rotation = rotation;
-
- final int naturalWidth = updatedDisplayInfo.getNaturalWidth();
- final int naturalHeight = updatedDisplayInfo.getNaturalHeight();
- updatedDisplayInfo.logicalWidth = naturalWidth;
- updatedDisplayInfo.logicalHeight = naturalHeight;
- return updatedDisplayInfo;
- }
-}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 3ffa62d..fbc8f73 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2587,9 +2587,6 @@
if (mService.isBooted() || mService.isBooting()) {
startSystemDecorations(display);
}
- // Drop any cached DisplayInfos associated with this display id - the values are now
- // out of date given this display added event.
- mWmService.mPossibleDisplayInfoMapper.removePossibleDisplayInfos(displayId);
}
}
@@ -2610,8 +2607,8 @@
if (displayContent == null) {
return;
}
+
displayContent.remove();
- mWmService.mPossibleDisplayInfoMapper.removePossibleDisplayInfos(displayId);
}
}
@@ -2623,9 +2620,6 @@
if (displayContent != null) {
displayContent.onDisplayChanged();
}
- // Drop any cached DisplayInfos associated with this display id - the values are now
- // out of date given this display changed event.
- mWmService.mPossibleDisplayInfoMapper.removePossibleDisplayInfos(displayId);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cc7485c..a8697a5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -47,6 +47,8 @@
import static android.provider.Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_270;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
@@ -330,11 +332,13 @@
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
+import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -1063,10 +1067,6 @@
final HighRefreshRateDenylist mHighRefreshRateDenylist;
- // Maintainer of a collection of all possible DisplayInfo for all configurations of the
- // logical displays.
- final PossibleDisplayInfoMapper mPossibleDisplayInfoMapper;
-
// If true, only the core apps and services are being launched because the device
// is in a special boot mode, such as being encrypted or waiting for a decryption password.
// For example, when this flag is true, there will be no wallpaper service.
@@ -1242,7 +1242,6 @@
mInputManager = inputManager; // Must be before createDisplayContentLocked.
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
- mPossibleDisplayInfoMapper = new PossibleDisplayInfoMapper(mDisplayManagerInternal);
mSurfaceControlFactory = surfaceControlFactory;
mTransactionFactory = transactionFactory;
@@ -8583,10 +8582,23 @@
+ " for getPossibleMaximumWindowMetrics");
return new ArrayList<>();
}
+ // TODO(181127261) DisplayInfo should be pushed from DisplayManager.
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ Slog.e(TAG, "Invalid displayId " + displayId
+ + " for getPossibleMaximumWindowMetrics");
+ return new ArrayList<>();
+ }
- // Retrieve the DisplayInfo for all possible rotations across all possible display
- // layouts.
- return List.copyOf(mPossibleDisplayInfoMapper.getPossibleDisplayInfos(displayId));
+ // TODO(181127261) DisplayManager should provide a DisplayInfo for each rotation
+ DisplayInfo currentDisplayInfo = dc.getDisplayInfo();
+ Set<DisplayInfo> displayInfoSet = new HashSet<>();
+ for (int rotation = ROTATION_0; rotation <= ROTATION_270; rotation++) {
+ currentDisplayInfo.rotation = rotation;
+ // TODO(181127261) Retrieve the device state from display stack.
+ displayInfoSet.add(new DisplayInfo(currentDisplayInfo));
+ }
+ return new ArrayList<DisplayInfo>(displayInfoSet);
}
} finally {
Binder.restoreCallingIdentity(origId);
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index 03eba9b..ee0723b 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -18,8 +18,6 @@
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
-import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
@@ -183,10 +181,8 @@
assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
assertEquals(mService.getPendingState(), Optional.empty());
assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertThat(mService.getSupportedStates()).asList().containsExactly(DEFAULT_DEVICE_STATE,
- OTHER_DEVICE_STATE);
- mProvider.notifySupportedDeviceStates(new DeviceState[]{DEFAULT_DEVICE_STATE});
+ mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE });
flushHandler();
// The current committed and requests states do not change because the current state remains
@@ -194,10 +190,9 @@
assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
assertEquals(mService.getPendingState(), Optional.empty());
assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertThat(mService.getSupportedStates()).asList().containsExactly(DEFAULT_DEVICE_STATE);
assertArrayEquals(callback.getLastNotifiedInfo().supportedStates,
- new int[]{DEFAULT_DEVICE_STATE.getIdentifier()});
+ new int[] { DEFAULT_DEVICE_STATE.getIdentifier() });
}
@Test
@@ -212,11 +207,9 @@
assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
assertEquals(mService.getPendingState(), Optional.empty());
assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertThat(mService.getSupportedStates()).asList().containsExactly(DEFAULT_DEVICE_STATE,
- OTHER_DEVICE_STATE);
- mProvider.notifySupportedDeviceStates(new DeviceState[]{DEFAULT_DEVICE_STATE,
- OTHER_DEVICE_STATE});
+ mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE,
+ OTHER_DEVICE_STATE });
flushHandler();
// The current committed and requests states do not change because the current state remains
@@ -224,8 +217,6 @@
assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
assertEquals(mService.getPendingState(), Optional.empty());
assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
- assertThat(mService.getSupportedStates()).asList().containsExactly(DEFAULT_DEVICE_STATE,
- OTHER_DEVICE_STATE);
// The callback wasn't notified about a change in supported states as the states have not
// changed.
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
index fbc1952..8279624 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -16,17 +16,12 @@
package com.android.server.display;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.DEFAULT_DISPLAY_GROUP;
-
import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED;
import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED;
import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED;
import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED;
import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED;
-import static com.google.common.truth.Truth.assertThat;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.ArgumentMatchers.eq;
@@ -60,7 +55,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
-import java.util.Set;
@SmallTest
@Presubmit
@@ -129,14 +123,14 @@
// add
LogicalDisplay displayAdded = add(device);
assertEquals(info(displayAdded).address, info(device).address);
- assertEquals(DEFAULT_DISPLAY, id(displayAdded));
+ assertEquals(Display.DEFAULT_DISPLAY, id(displayAdded));
// remove
mDisplayDeviceRepo.onDisplayDeviceEvent(device, DISPLAY_DEVICE_EVENT_REMOVED);
verify(mListenerMock).onLogicalDisplayEventLocked(
mDisplayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_REMOVED));
LogicalDisplay displayRemoved = mDisplayCaptor.getValue();
- assertEquals(DEFAULT_DISPLAY, id(displayRemoved));
+ assertEquals(Display.DEFAULT_DISPLAY, id(displayRemoved));
assertEquals(displayAdded, displayRemoved);
}
@@ -161,11 +155,11 @@
LogicalDisplay display1 = add(device1);
assertEquals(info(display1).address, info(device1).address);
- assertNotEquals(DEFAULT_DISPLAY, id(display1));
+ assertNotEquals(Display.DEFAULT_DISPLAY, id(display1));
LogicalDisplay display2 = add(device2);
assertEquals(info(display2).address, info(device2).address);
- assertEquals(DEFAULT_DISPLAY, id(display2));
+ assertEquals(Display.DEFAULT_DISPLAY, id(display2));
}
@Test
@@ -177,12 +171,12 @@
LogicalDisplay display1 = add(device1);
assertEquals(info(display1).address, info(device1).address);
- assertEquals(DEFAULT_DISPLAY, id(display1));
+ assertEquals(Display.DEFAULT_DISPLAY, id(display1));
LogicalDisplay display2 = add(device2);
assertEquals(info(display2).address, info(device2).address);
// Despite the flags, we can only have one default display
- assertNotEquals(DEFAULT_DISPLAY, id(display2));
+ assertNotEquals(Display.DEFAULT_DISPLAY, id(display2));
}
@Test
@@ -195,67 +189,7 @@
int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID);
assertEquals(3, ids.length);
Arrays.sort(ids);
- assertEquals(DEFAULT_DISPLAY, ids[0]);
- }
-
- @Test
- public void testGetDisplayInfoForStateLocked_oneDisplayGroup_internalType() {
- add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
- DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
- add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800,
- DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
- add(createDisplayDevice(Display.TYPE_INTERNAL, 700, 800,
- DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
-
- Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked(
- DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP);
- assertThat(displayInfos.size()).isEqualTo(3);
- for (DisplayInfo displayInfo : displayInfos) {
- assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY);
- assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP);
- assertThat(displayInfo.logicalWidth).isAnyOf(600, 200, 700);
- assertThat(displayInfo.logicalHeight).isEqualTo(800);
- }
- }
-
- @Test
- public void testGetDisplayInfoForStateLocked_oneDisplayGroup_differentTypes() {
- add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
- DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
- add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800,
- DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
- add(createDisplayDevice(Display.TYPE_EXTERNAL, 700, 800,
- DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
-
- Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked(
- DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP);
- assertThat(displayInfos.size()).isEqualTo(2);
- for (DisplayInfo displayInfo : displayInfos) {
- assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY);
- assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP);
- assertThat(displayInfo.logicalWidth).isAnyOf(600, 200);
- assertThat(displayInfo.logicalHeight).isEqualTo(800);
- }
- }
-
- @Test
- public void testGetDisplayInfoForStateLocked_multipleDisplayGroups_defaultGroup() {
- add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
- DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
- add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800,
- DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
- add(createDisplayDevice(Display.TYPE_VIRTUAL, 700, 800,
- DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP));
-
- Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked(
- DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP);
- assertThat(displayInfos.size()).isEqualTo(2);
- for (DisplayInfo displayInfo : displayInfos) {
- assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY);
- assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP);
- assertThat(displayInfo.logicalWidth).isAnyOf(600, 200);
- assertThat(displayInfo.logicalHeight).isEqualTo(800);
- }
+ assertEquals(Display.DEFAULT_DISPLAY, ids[0]);
}
@Test
@@ -265,11 +199,11 @@
LogicalDisplay display2 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0));
LogicalDisplay display3 = add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0));
- assertEquals(DEFAULT_DISPLAY_GROUP,
+ assertEquals(Display.DEFAULT_DISPLAY_GROUP,
mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display1)));
- assertEquals(DEFAULT_DISPLAY_GROUP,
+ assertEquals(Display.DEFAULT_DISPLAY_GROUP,
mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display2)));
- assertEquals(DEFAULT_DISPLAY_GROUP,
+ assertEquals(Display.DEFAULT_DISPLAY_GROUP,
mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3)));
}
@@ -284,11 +218,11 @@
DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
LogicalDisplay display3 = add(device3);
- assertEquals(DEFAULT_DISPLAY_GROUP,
+ assertEquals(Display.DEFAULT_DISPLAY_GROUP,
mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display1)));
- assertEquals(DEFAULT_DISPLAY_GROUP,
+ assertEquals(Display.DEFAULT_DISPLAY_GROUP,
mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display2)));
- assertNotEquals(DEFAULT_DISPLAY_GROUP,
+ assertNotEquals(Display.DEFAULT_DISPLAY_GROUP,
mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3)));
// Now switch it back to the default group by removing the flag and issuing an update
@@ -297,7 +231,7 @@
mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED);
// Verify the new group is correct.
- assertEquals(DEFAULT_DISPLAY_GROUP,
+ assertEquals(Display.DEFAULT_DISPLAY_GROUP,
mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3)));
}
@@ -353,14 +287,14 @@
// add
LogicalDisplay displayAdded = add(device);
assertEquals(info(displayAdded).address, info(device).address);
- assertNotEquals(DEFAULT_DISPLAY, id(displayAdded));
+ assertNotEquals(Display.DEFAULT_DISPLAY, id(displayAdded));
// remove
mDisplayDeviceRepo.onDisplayDeviceEvent(device, DISPLAY_DEVICE_EVENT_REMOVED);
verify(mListenerMock).onLogicalDisplayEventLocked(
mDisplayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_REMOVED));
LogicalDisplay displayRemoved = mDisplayCaptor.getValue();
- assertNotEquals(DEFAULT_DISPLAY, id(displayRemoved));
+ assertNotEquals(Display.DEFAULT_DISPLAY, id(displayRemoved));
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java b/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java
deleted file mode 100644
index 6e00568..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.FLAG_PRESENTATION;
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.when;
-
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-import android.util.ArraySet;
-import android.view.DisplayInfo;
-
-import androidx.test.filters.MediumTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Set;
-
-
-/**
- * Tests for {@link PossibleDisplayInfoMapper}.
- *
- * Build/Install/Run:
- * atest WmTests:PossibleDisplayInfoMapperTests
- */
-@MediumTest
-@Presubmit
-@RunWith(WindowTestRunner.class)
-public class PossibleDisplayInfoMapperTests extends WindowTestsBase {
-
- private PossibleDisplayInfoMapper mDisplayInfoMapper;
- private final Set<DisplayInfo> mPossibleDisplayInfo = new ArraySet<>();
- private DisplayInfo mDefaultDisplayInfo;
- private DisplayInfo mSecondDisplayInfo;
-
- @Before
- public void setUp() throws Exception {
- mDisplayInfoMapper = mWm.mPossibleDisplayInfoMapper;
- final DisplayInfo baseDisplayInfo = mWm.mRoot.getDisplayContent(
- DEFAULT_DISPLAY).getDisplayInfo();
- when(mWm.mDisplayManagerInternal.getPossibleDisplayInfo(anyInt())).thenReturn(
- mPossibleDisplayInfo);
-
- mDefaultDisplayInfo = new DisplayInfo(baseDisplayInfo);
- initializeDisplayInfo(mDefaultDisplayInfo, DEFAULT_DISPLAY, new Rect(0, 0, 500, 800));
- mSecondDisplayInfo = new DisplayInfo(baseDisplayInfo);
- // Use the same display id for any display in the same group, due to the assumption that
- // any display in the same grouped can be swapped out for each other (while maintaining the
- // display id).
- initializeDisplayInfo(mSecondDisplayInfo, DEFAULT_DISPLAY, new Rect(0, 0, 600, 1600));
- mSecondDisplayInfo.flags |= FLAG_PRESENTATION;
- }
-
- @Test
- public void testInitialization_isEmpty() {
- // Empty after initializing.
- assertThat(mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY)).isEmpty();
-
- // Still empty after updating.
- mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
- assertThat(mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY)).isEmpty();
- }
-
- @Test
- public void testUpdatePossibleDisplayInfos_singleDisplay() {
- mPossibleDisplayInfo.add(mDefaultDisplayInfo);
- mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
-
- Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY);
- // An entry for each possible rotation, for a display that can be in a single state.
- assertThat(displayInfos.size()).isEqualTo(4);
- assertPossibleDisplayInfoEntries(displayInfos, mDefaultDisplayInfo);
- }
-
- @Test
- public void testUpdatePossibleDisplayInfos_secondDisplayAdded_sameGroup() {
- mPossibleDisplayInfo.add(mDefaultDisplayInfo);
- mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
-
- assertThat(mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY).size()).isEqualTo(4);
-
- // Add another display layout to the set of supported states.
- mPossibleDisplayInfo.add(mSecondDisplayInfo);
- mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
-
- Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY);
- Set<DisplayInfo> defaultDisplayInfos = new ArraySet<>();
- Set<DisplayInfo> secondDisplayInfos = new ArraySet<>();
- for (DisplayInfo di : displayInfos) {
- if ((di.flags & FLAG_PRESENTATION) != 0) {
- secondDisplayInfos.add(di);
- } else {
- defaultDisplayInfos.add(di);
- }
- }
- // An entry for each possible rotation, for the default display.
- assertThat(defaultDisplayInfos).hasSize(4);
- assertPossibleDisplayInfoEntries(defaultDisplayInfos, mDefaultDisplayInfo);
-
- // An entry for each possible rotation, for the second display.
- assertThat(secondDisplayInfos).hasSize(4);
- assertPossibleDisplayInfoEntries(secondDisplayInfos, mSecondDisplayInfo);
- }
-
- @Test
- public void testUpdatePossibleDisplayInfos_secondDisplayAdded_differentGroup() {
- mPossibleDisplayInfo.add(mDefaultDisplayInfo);
- mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
-
- assertThat(mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY).size()).isEqualTo(4);
-
- // Add another display to a different group.
- mSecondDisplayInfo.displayId = DEFAULT_DISPLAY + 1;
- mSecondDisplayInfo.displayGroupId = mDefaultDisplayInfo.displayGroupId + 1;
- mPossibleDisplayInfo.add(mSecondDisplayInfo);
- mDisplayInfoMapper.updatePossibleDisplayInfos(mSecondDisplayInfo.displayId);
-
- Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY);
- // An entry for each possible rotation, for the default display.
- assertThat(displayInfos).hasSize(4);
- assertPossibleDisplayInfoEntries(displayInfos, mDefaultDisplayInfo);
-
- Set<DisplayInfo> secondStateEntries =
- mDisplayInfoMapper.getPossibleDisplayInfos(mSecondDisplayInfo.displayId);
- // An entry for each possible rotation, for the second display.
- assertThat(secondStateEntries).hasSize(4);
- assertPossibleDisplayInfoEntries(secondStateEntries, mSecondDisplayInfo);
- }
-
- private static void initializeDisplayInfo(DisplayInfo outDisplayInfo, int displayId,
- Rect logicalBounds) {
- outDisplayInfo.displayId = displayId;
- outDisplayInfo.rotation = ROTATION_0;
- outDisplayInfo.logicalWidth = logicalBounds.width();
- outDisplayInfo.logicalHeight = logicalBounds.height();
- }
-
- private static void assertPossibleDisplayInfoEntries(Set<DisplayInfo> displayInfos,
- DisplayInfo expectedDisplayInfo) {
- boolean[] seenEveryRotation = new boolean[4];
- for (DisplayInfo displayInfo : displayInfos) {
- final int rotation = displayInfo.rotation;
- seenEveryRotation[rotation] = true;
- assertThat(displayInfo.displayId).isEqualTo(expectedDisplayInfo.displayId);
- assertEqualsRotatedDisplayInfo(displayInfo, expectedDisplayInfo);
- }
- assertThat(seenEveryRotation).isEqualTo(new boolean[]{true, true, true, true});
- }
-
- private static void assertEqualsRotatedDisplayInfo(DisplayInfo actual, DisplayInfo expected) {
- if (actual.rotation == ROTATION_0 || actual.rotation == ROTATION_180) {
- assertThat(actual.logicalWidth).isEqualTo(expected.logicalWidth);
- assertThat(actual.logicalHeight).isEqualTo(expected.logicalHeight);
- } else {
- assertThat(actual.logicalWidth).isEqualTo(expected.logicalHeight);
- assertThat(actual.logicalHeight).isEqualTo(expected.logicalWidth);
- }
- }
-}