summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityOptions.java24
-rw-r--r--core/java/android/view/InsetsState.java13
-rw-r--r--core/java/com/android/internal/app/LocaleStore.java12
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl8
-rw-r--r--core/java/com/android/internal/statusbar/RegisterStatusBarResult.java10
-rw-r--r--core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java13
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java85
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java182
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java86
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java4
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt144
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt165
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt8
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt4
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java14
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java14
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java6
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java26
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java31
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java53
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java193
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java21
-rw-r--r--services/core/java/com/android/server/wm/InsetsStateController.java169
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java4
40 files changed, 832 insertions, 639 deletions
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index b3337b6352e1..3b882571507f 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -343,6 +343,13 @@ public class ActivityOptions extends ComponentOptions {
"android:activity.applyActivityFlagsForBubbles";
/**
+ * Indicates to apply {@link Intent#FLAG_ACTIVITY_MULTIPLE_TASK} to the launching shortcut.
+ * @hide
+ */
+ private static final String KEY_APPLY_MULTIPLE_TASK_FLAG_FOR_SHORTCUT =
+ "android:activity.applyMultipleTaskFlagForShortcut";
+
+ /**
* For Activity transitions, the calling Activity's TransitionListener used to
* notify the called Activity when the shared element and the exit transitions
* complete.
@@ -476,6 +483,7 @@ public class ActivityOptions extends ComponentOptions {
private boolean mShareIdentity = false;
private boolean mDisallowEnterPictureInPictureWhileLaunching;
private boolean mApplyActivityFlagsForBubbles;
+ private boolean mApplyMultipleTaskFlagForShortcut;
private boolean mTaskAlwaysOnTop;
private boolean mTaskOverlay;
private boolean mTaskOverlayCanResume;
@@ -1278,6 +1286,8 @@ public class ActivityOptions extends ComponentOptions {
KEY_DISALLOW_ENTER_PICTURE_IN_PICTURE_WHILE_LAUNCHING, false);
mApplyActivityFlagsForBubbles = opts.getBoolean(
KEY_APPLY_ACTIVITY_FLAGS_FOR_BUBBLES, false);
+ mApplyMultipleTaskFlagForShortcut = opts.getBoolean(
+ KEY_APPLY_MULTIPLE_TASK_FLAG_FOR_SHORTCUT, false);
if (opts.containsKey(KEY_ANIM_SPECS)) {
Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS);
mAnimSpecs = new AppTransitionAnimationSpec[specs.length];
@@ -1906,6 +1916,16 @@ public class ActivityOptions extends ComponentOptions {
return mApplyActivityFlagsForBubbles;
}
+ /** @hide */
+ public void setApplyMultipleTaskFlagForShortcut(boolean apply) {
+ mApplyMultipleTaskFlagForShortcut = apply;
+ }
+
+ /** @hide */
+ public boolean isApplyMultipleTaskFlagForShortcut() {
+ return mApplyMultipleTaskFlagForShortcut;
+ }
+
/**
* Sets a launch cookie that can be used to track the activity and task that are launch as a
* result of this option. If the launched activity is a trampoline that starts another activity
@@ -2262,6 +2282,10 @@ public class ActivityOptions extends ComponentOptions {
if (mApplyActivityFlagsForBubbles) {
b.putBoolean(KEY_APPLY_ACTIVITY_FLAGS_FOR_BUBBLES, mApplyActivityFlagsForBubbles);
}
+ if (mApplyMultipleTaskFlagForShortcut) {
+ b.putBoolean(KEY_APPLY_MULTIPLE_TASK_FLAG_FOR_SHORTCUT,
+ mApplyMultipleTaskFlagForShortcut);
+ }
if (mAnimSpecs != null) {
b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 70a773994926..ba7d823750a3 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -781,19 +781,6 @@ public class InsetsState implements Parcelable {
}
}
- public static boolean containsType(@InternalInsetsType int[] types,
- @InternalInsetsType int type) {
- if (types == null) {
- return false;
- }
- for (int t : types) {
- if (t == type) {
- return true;
- }
- }
- return false;
- }
-
public void dump(String prefix, PrintWriter pw) {
final String newPrefix = prefix + " ";
pw.println(prefix + "InsetsState");
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index bcff9078ddda..298230a85060 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -563,6 +563,18 @@ public class LocaleStore {
String id = locale.toLanguageTag();
LocaleInfo result;
if (!sLocaleCache.containsKey(id)) {
+ // Locale preferences can modify the language tag to current system languages, so we
+ // need to check the input locale without extra u extension except numbering system.
+ Locale filteredLocale = new Locale.Builder()
+ .setLocale(locale.stripExtensions())
+ .setUnicodeLocaleKeyword("nu", locale.getUnicodeLocaleType("nu"))
+ .build();
+ if (sLocaleCache.containsKey(filteredLocale.toLanguageTag())) {
+ result = new LocaleInfo(locale);
+ // This locale is included in supported locales, so set translated be true here.
+ result.mIsTranslated = true;
+ return result;
+ }
result = new LocaleInfo(locale);
sLocaleCache.put(id, result);
} else {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 1c85ca2bb269..b529a1016464 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -214,11 +214,11 @@ oneway interface IStatusBar
* bar and navigation bar which are temporarily visible to the user.
*
* @param displayId the ID of the display to notify.
- * @param types the internal insets types of the bars are about to show transiently.
+ * @param types the insets types of the bars are about to show transiently.
* @param isGestureOnSystemBar whether the gesture to show the transient bar was a gesture on
* one of the bars itself.
*/
- void showTransient(int displayId, in int[] types, boolean isGestureOnSystemBar);
+ void showTransient(int displayId, int types, boolean isGestureOnSystemBar);
/**
* Notifies System UI to abort the transient state of system bars, which prevents the bars being
@@ -226,9 +226,9 @@ oneway interface IStatusBar
* bars again.
*
* @param displayId the ID of the display to notify.
- * @param types the internal insets types of the bars are about to abort the transient state.
+ * @param types the insets types of the bars are about to abort the transient state.
*/
- void abortTransient(int displayId, in int[] types);
+ void abortTransient(int displayId, int types);
/**
* Show a warning that the device is about to go to sleep due to user inactivity.
diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
index 54221ce92dc4..4f827cda6afa 100644
--- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
+++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
@@ -16,7 +16,6 @@
package com.android.internal.statusbar;
-import android.annotation.NonNull;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -41,15 +40,14 @@ public final class RegisterStatusBarResult implements Parcelable {
public final int mBehavior;
public final int mRequestedVisibleTypes;
public final String mPackageName;
- public final int[] mTransientBarTypes;
+ public final int mTransientBarTypes;
public final LetterboxDetails[] mLetterboxDetails;
public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1,
int appearance, AppearanceRegion[] appearanceRegions, int imeWindowVis,
int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2, IBinder imeToken,
boolean navbarColorManagedByIme, int behavior, int requestedVisibleTypes,
- String packageName, @NonNull int[] transientBarTypes,
- LetterboxDetails[] letterboxDetails) {
+ String packageName, int transientBarTypes, LetterboxDetails[] letterboxDetails) {
mIcons = new ArrayMap<>(icons);
mDisabledFlags1 = disabledFlags1;
mAppearance = appearance;
@@ -87,7 +85,7 @@ public final class RegisterStatusBarResult implements Parcelable {
dest.writeInt(mBehavior);
dest.writeInt(mRequestedVisibleTypes);
dest.writeString(mPackageName);
- dest.writeIntArray(mTransientBarTypes);
+ dest.writeInt(mTransientBarTypes);
dest.writeParcelableArray(mLetterboxDetails, flags);
}
@@ -113,7 +111,7 @@ public final class RegisterStatusBarResult implements Parcelable {
final int behavior = source.readInt();
final int requestedVisibleTypes = source.readInt();
final String packageName = source.readString();
- final int[] transientBarTypes = source.createIntArray();
+ final int transientBarTypes = source.readInt();
final LetterboxDetails[] letterboxDetails =
source.readParcelableArray(null, LetterboxDetails.class);
return new RegisterStatusBarResult(icons, disabledFlags1, appearance,
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
index 048c48bc45fa..f79ba28d946f 100644
--- a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
+++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
@@ -67,7 +67,7 @@ public class RegisterStatusBarResultTest {
BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE,
WindowInsets.Type.defaultVisible(),
"test" /* packageName */,
- new int[0] /* transientBarTypes */,
+ 0 /* transientBarTypes */,
new LetterboxDetails[] {letterboxDetails});
final RegisterStatusBarResult copy = clone(original);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 45b234a6398a..f616e6f64750 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -699,19 +699,6 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
return bounds.width() > bounds.height();
}
- /** Reverse the split position. */
- @SplitPosition
- public static int reversePosition(@SplitPosition int position) {
- switch (position) {
- case SPLIT_POSITION_TOP_OR_LEFT:
- return SPLIT_POSITION_BOTTOM_OR_RIGHT;
- case SPLIT_POSITION_BOTTOM_OR_RIGHT:
- return SPLIT_POSITION_TOP_OR_LEFT;
- default:
- return SPLIT_POSITION_UNDEFINED;
- }
- }
-
/**
* Return if this layout is landscape.
*/
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
new file mode 100644
index 000000000000..042721c97053
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitScreenUtils.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2023 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.common.split;
+
+import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
+import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.PendingIntent;
+import android.content.Intent;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.wm.shell.ShellTaskOrganizer;
+
+/** Helper utility class for split screen components to use. */
+public class SplitScreenUtils {
+ /** Reverse the split position. */
+ @SplitScreenConstants.SplitPosition
+ public static int reverseSplitPosition(@SplitScreenConstants.SplitPosition int position) {
+ switch (position) {
+ case SPLIT_POSITION_TOP_OR_LEFT:
+ return SPLIT_POSITION_BOTTOM_OR_RIGHT;
+ case SPLIT_POSITION_BOTTOM_OR_RIGHT:
+ return SPLIT_POSITION_TOP_OR_LEFT;
+ case SPLIT_POSITION_UNDEFINED:
+ default:
+ return SPLIT_POSITION_UNDEFINED;
+ }
+ }
+
+ /** Returns true if the task is valid for split screen. */
+ public static boolean isValidToSplit(ActivityManager.RunningTaskInfo taskInfo) {
+ return taskInfo != null && taskInfo.supportsMultiWindow
+ && ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType())
+ && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode());
+ }
+
+ /** Retrieve package name from an intent */
+ @Nullable
+ public static String getPackageName(Intent intent) {
+ if (intent == null || intent.getComponent() == null) {
+ return null;
+ }
+ return intent.getComponent().getPackageName();
+ }
+
+ /** Retrieve package name from a PendingIntent */
+ @Nullable
+ public static String getPackageName(PendingIntent pendingIntent) {
+ if (pendingIntent == null || pendingIntent.getIntent() == null) {
+ return null;
+ }
+ return getPackageName(pendingIntent.getIntent());
+ }
+
+ /** Retrieve package name from a taskId */
+ @Nullable
+ public static String getPackageName(int taskId, ShellTaskOrganizer taskOrganizer) {
+ final ActivityManager.RunningTaskInfo taskInfo = taskOrganizer.getRunningTaskInfo(taskId);
+ return taskInfo != null ? getPackageName(taskInfo.baseIntent) : null;
+ }
+
+ /** Returns true if they are the same package. */
+ public static boolean samePackage(String packageName1, String packageName2) {
+ return packageName1 != null && packageName1.equals(packageName2);
+ }
+}
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 21eeaa2cafb3..7cb5cf2ea177 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
@@ -28,6 +28,9 @@ import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTas
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.common.split.SplitScreenUtils.isValidToSplit;
+import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
+import static com.android.wm.shell.common.split.SplitScreenUtils.samePackage;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
@@ -39,11 +42,8 @@ import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.graphics.Rect;
import android.os.Bundle;
@@ -82,8 +82,8 @@ import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ExternalThread;
-import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
+import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -318,10 +318,6 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
return mStageCoordinator;
}
- public boolean isValidToEnterSplitScreen(@NonNull ActivityManager.RunningTaskInfo taskInfo) {
- return mStageCoordinator.isValidToEnterSplitScreen(taskInfo);
- }
-
@Nullable
public ActivityManager.RunningTaskInfo getTaskInfo(@SplitPosition int splitPosition) {
if (!isSplitScreenVisible() || splitPosition == SPLIT_POSITION_UNDEFINED) {
@@ -480,39 +476,54 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
@Override
public void startShortcut(String packageName, String shortcutId, @SplitPosition int position,
@Nullable Bundle options, UserHandle user) {
- IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
- @Override
- public void onAnimationStart(@WindowManager.TransitionOldType int transit,
- RemoteAnimationTarget[] apps,
- RemoteAnimationTarget[] wallpapers,
- RemoteAnimationTarget[] nonApps,
- final IRemoteAnimationFinishedCallback finishedCallback) {
- try {
- finishedCallback.onAnimationFinished();
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to invoke onAnimationFinished", e);
- }
- final WindowContainerTransaction evictWct = new WindowContainerTransaction();
- mStageCoordinator.prepareEvictNonOpeningChildTasks(position, apps, evictWct);
- mSyncQueue.queue(evictWct);
+ if (options == null) options = new Bundle();
+ final ActivityOptions activityOptions = ActivityOptions.fromBundle(options);
+
+ if (samePackage(packageName, getPackageName(reverseSplitPosition(position)))) {
+ if (supportMultiInstancesSplit(packageName)) {
+ activityOptions.setApplyMultipleTaskFlagForShortcut(true);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
+ } else if (isSplitScreenVisible()) {
+ mStageCoordinator.switchSplitPosition("startShortcut");
+ return;
+ } else {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "Cancel entering split as not supporting multi-instances");
+ Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
+ Toast.LENGTH_SHORT).show();
+ return;
}
- @Override
- public void onAnimationCancelled(boolean isKeyguardOccluded) {
+ }
+
+ mStageCoordinator.startShortcut(packageName, shortcutId, position,
+ activityOptions.toBundle(), user);
+ }
+
+ void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo,
+ @Nullable Bundle options1, int taskId, @Nullable Bundle options2,
+ @SplitPosition int splitPosition, float splitRatio, RemoteAnimationAdapter adapter,
+ InstanceId instanceId) {
+ if (options1 == null) options1 = new Bundle();
+ final ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
+
+ final String packageName1 = shortcutInfo.getPackage();
+ final String packageName2 = SplitScreenUtils.getPackageName(taskId, mTaskOrganizer);
+ if (samePackage(packageName1, packageName2)) {
+ if (supportMultiInstancesSplit(shortcutInfo.getPackage())) {
+ activityOptions.setApplyMultipleTaskFlagForShortcut(true);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
+ } else {
+ taskId = INVALID_TASK_ID;
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "Cancel entering split as not supporting multi-instances");
+ Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
+ Toast.LENGTH_SHORT).show();
}
- };
- options = mStageCoordinator.resolveStartStage(STAGE_TYPE_UNDEFINED, position, options,
- null /* wct */);
- RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(wrapper,
- 0 /* duration */, 0 /* statusBarTransitionDelay */);
- ActivityOptions activityOptions = ActivityOptions.fromBundle(options);
- activityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
- try {
- LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
- launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */,
- activityOptions.toBundle(), user);
- } catch (ActivityNotFoundException e) {
- Slog.e(TAG, "Failed to launch shortcut", e);
}
+
+ mStageCoordinator.startShortcutAndTaskWithLegacyTransition(shortcutInfo,
+ activityOptions.toBundle(), taskId, options2, splitPosition, splitRatio, adapter,
+ instanceId);
}
/**
@@ -530,8 +541,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
@SplitPosition int splitPosition, float splitRatio, RemoteAnimationAdapter adapter,
InstanceId instanceId) {
Intent fillInIntent = null;
- if (launchSameAppAdjacently(pendingIntent, taskId)) {
- if (supportMultiInstancesSplit(pendingIntent.getIntent().getComponent())) {
+ final String packageName1 = SplitScreenUtils.getPackageName(pendingIntent);
+ final String packageName2 = SplitScreenUtils.getPackageName(taskId, mTaskOrganizer);
+ if (samePackage(packageName1, packageName2)) {
+ if (supportMultiInstancesSplit(packageName1)) {
fillInIntent = new Intent();
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
@@ -551,8 +564,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition,
float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
Intent fillInIntent = null;
- if (launchSameAppAdjacently(pendingIntent, taskId)) {
- if (supportMultiInstancesSplit(pendingIntent.getIntent().getComponent())) {
+ final String packageName1 = SplitScreenUtils.getPackageName(pendingIntent);
+ final String packageName2 = SplitScreenUtils.getPackageName(taskId, mTaskOrganizer);
+ if (samePackage(packageName1, packageName2)) {
+ if (supportMultiInstancesSplit(packageName1)) {
fillInIntent = new Intent();
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
@@ -573,8 +588,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
Intent fillInIntent1 = null;
Intent fillInIntent2 = null;
- if (launchSameAppAdjacently(pendingIntent1, pendingIntent2)) {
- if (supportMultiInstancesSplit(pendingIntent1.getIntent().getComponent())) {
+ final String packageName1 = SplitScreenUtils.getPackageName(pendingIntent1);
+ final String packageName2 = SplitScreenUtils.getPackageName(pendingIntent2);
+ if (samePackage(packageName1, packageName2)) {
+ if (supportMultiInstancesSplit(packageName1)) {
fillInIntent1 = new Intent();
fillInIntent1.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
fillInIntent2 = new Intent();
@@ -602,13 +619,15 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
if (fillInIntent == null) fillInIntent = new Intent();
fillInIntent.addFlags(FLAG_ACTIVITY_NO_USER_ACTION);
- if (launchSameAppAdjacently(position, intent)) {
- final ComponentName launching = intent.getIntent().getComponent();
- if (supportMultiInstancesSplit(launching)) {
+ final String packageName1 = SplitScreenUtils.getPackageName(intent);
+ final String packageName2 = getPackageName(reverseSplitPosition(position));
+ if (SplitScreenUtils.samePackage(packageName1, packageName2)) {
+ if (supportMultiInstancesSplit(packageName1)) {
// To prevent accumulating large number of instances in the background, reuse task
// in the background with priority.
final ActivityManager.RecentTaskInfo taskInfo = mRecentTasksOptional
- .map(recentTasks -> recentTasks.findTaskInBackground(launching))
+ .map(recentTasks -> recentTasks.findTaskInBackground(
+ intent.getIntent().getComponent()))
.orElse(null);
if (taskInfo != null) {
startTask(taskInfo.taskId, position, options);
@@ -636,63 +655,32 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
mStageCoordinator.startIntent(intent, fillInIntent, position, options);
}
+ /** Retrieve package name of a specific split position if split screen is activated, otherwise
+ * returns the package name of the top running task. */
@Nullable
- private String getPackageName(Intent intent) {
- if (intent == null || intent.getComponent() == null) {
- return null;
- }
- return intent.getComponent().getPackageName();
- }
-
- private boolean launchSameAppAdjacently(@SplitPosition int position,
- PendingIntent pendingIntent) {
- ActivityManager.RunningTaskInfo adjacentTaskInfo = null;
+ private String getPackageName(@SplitPosition int position) {
+ ActivityManager.RunningTaskInfo taskInfo;
if (isSplitScreenVisible()) {
- adjacentTaskInfo = getTaskInfo(SplitLayout.reversePosition(position));
+ taskInfo = getTaskInfo(position);
} else {
- adjacentTaskInfo = mRecentTasksOptional
- .map(recentTasks -> recentTasks.getTopRunningTask()).orElse(null);
- if (!isValidToEnterSplitScreen(adjacentTaskInfo)) {
- return false;
+ taskInfo = mRecentTasksOptional
+ .map(recentTasks -> recentTasks.getTopRunningTask())
+ .orElse(null);
+ if (!isValidToSplit(taskInfo)) {
+ return null;
}
}
- if (adjacentTaskInfo == null) {
- return false;
- }
-
- final String targetPackageName = getPackageName(pendingIntent.getIntent());
- final String adjacentPackageName = getPackageName(adjacentTaskInfo.baseIntent);
- return targetPackageName != null && targetPackageName.equals(adjacentPackageName);
- }
-
- private boolean launchSameAppAdjacently(PendingIntent pendingIntent, int taskId) {
- final ActivityManager.RunningTaskInfo adjacentTaskInfo =
- mTaskOrganizer.getRunningTaskInfo(taskId);
- if (adjacentTaskInfo == null) {
- return false;
- }
- final String targetPackageName = getPackageName(pendingIntent.getIntent());
- final String adjacentPackageName = getPackageName(adjacentTaskInfo.baseIntent);
- return targetPackageName != null && targetPackageName.equals(adjacentPackageName);
- }
-
- private boolean launchSameAppAdjacently(PendingIntent pendingIntent1,
- PendingIntent pendingIntent2) {
- final String targetPackageName = getPackageName(pendingIntent1.getIntent());
- final String adjacentPackageName = getPackageName(pendingIntent2.getIntent());
- return targetPackageName != null && targetPackageName.equals(adjacentPackageName);
+ return taskInfo != null ? SplitScreenUtils.getPackageName(taskInfo.baseIntent) : null;
}
@VisibleForTesting
- /** Returns {@code true} if the component supports multi-instances split. */
- boolean supportMultiInstancesSplit(@Nullable ComponentName launching) {
- if (launching == null) return false;
-
- final String packageName = launching.getPackageName();
- for (int i = 0; i < mAppsSupportMultiInstances.length; i++) {
- if (mAppsSupportMultiInstances[i].equals(packageName)) {
- return true;
+ boolean supportMultiInstancesSplit(String packageName) {
+ if (packageName != null) {
+ for (int i = 0; i < mAppsSupportMultiInstances.length; i++) {
+ if (mAppsSupportMultiInstances[i].equals(packageName)) {
+ return true;
+ }
}
}
@@ -1011,7 +999,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
InstanceId instanceId) {
executeRemoteCallWithTaskPermission(mController,
"startShortcutAndTaskWithLegacyTransition", (controller) ->
- controller.mStageCoordinator.startShortcutAndTaskWithLegacyTransition(
+ controller.startShortcutAndTaskWithLegacyTransition(
shortcutInfo, options1, taskId, options2, splitPosition,
splitRatio, adapter, instanceId));
}
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 9624ae9b741b..5a9170b48ede 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
@@ -36,12 +36,11 @@ import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER;
-import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
-import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_WINDOWING_MODES;
import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
+import static com.android.wm.shell.common.split.SplitScreenUtils.reverseSplitPosition;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
@@ -76,8 +75,10 @@ import android.app.ActivityOptions;
import android.app.IActivityTaskManager;
import android.app.PendingIntent;
import android.app.WindowConfiguration;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -87,6 +88,7 @@ import android.os.Debug;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
import android.view.Choreographer;
@@ -370,7 +372,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
int sideStagePosition;
if (stageType == STAGE_TYPE_MAIN) {
targetStage = mMainStage;
- sideStagePosition = SplitLayout.reversePosition(stagePosition);
+ sideStagePosition = reverseSplitPosition(stagePosition);
} else if (stageType == STAGE_TYPE_SIDE) {
targetStage = mSideStage;
sideStagePosition = stagePosition;
@@ -428,6 +430,72 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return mLogger;
}
+ void startShortcut(String packageName, String shortcutId, @SplitPosition int position,
+ Bundle options, UserHandle user) {
+ final boolean isEnteringSplit = !isSplitActive();
+
+ IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
+ @Override
+ public void onAnimationStart(@WindowManager.TransitionOldType int transit,
+ RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers,
+ RemoteAnimationTarget[] nonApps,
+ final IRemoteAnimationFinishedCallback finishedCallback) {
+ boolean openingToSide = false;
+ if (apps != null) {
+ for (int i = 0; i < apps.length; ++i) {
+ if (apps[i].mode == MODE_OPENING
+ && mSideStage.containsTask(apps[i].taskId)) {
+ openingToSide = true;
+ break;
+ }
+ }
+ }
+
+ if (isEnteringSplit && !openingToSide) {
+ mMainExecutor.execute(() -> exitSplitScreen(
+ mSideStage.getChildCount() == 0 ? mMainStage : mSideStage,
+ EXIT_REASON_UNKNOWN));
+ }
+
+ if (finishedCallback != null) {
+ try {
+ finishedCallback.onAnimationFinished();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error finishing legacy transition: ", e);
+ }
+ }
+
+ if (!isEnteringSplit && openingToSide) {
+ final WindowContainerTransaction evictWct = new WindowContainerTransaction();
+ prepareEvictNonOpeningChildTasks(position, apps, evictWct);
+ mSyncQueue.queue(evictWct);
+ }
+ }
+ @Override
+ public void onAnimationCancelled(boolean isKeyguardOccluded) {
+ if (isEnteringSplit) {
+ mMainExecutor.execute(() -> exitSplitScreen(
+ mSideStage.getChildCount() == 0 ? mMainStage : mSideStage,
+ EXIT_REASON_UNKNOWN));
+ }
+ }
+ };
+ options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options,
+ null /* wct */);
+ RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(wrapper,
+ 0 /* duration */, 0 /* statusBarTransitionDelay */);
+ ActivityOptions activityOptions = ActivityOptions.fromBundle(options);
+ activityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
+ try {
+ LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
+ launcherApps.startShortcut(packageName, shortcutId, null /* sourceBounds */,
+ activityOptions.toBundle(), user);
+ } catch (ActivityNotFoundException e) {
+ Slog.e(TAG, "Failed to launch shortcut", e);
+ }
+ }
+
/** Launches an activity into split. */
void startIntent(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
@Nullable Bundle options) {
@@ -899,7 +967,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
case STAGE_TYPE_MAIN: {
if (position != SPLIT_POSITION_UNDEFINED) {
// Set the side stage opposite of what we want to the main stage.
- setSideStagePosition(SplitLayout.reversePosition(position), wct);
+ setSideStagePosition(reverseSplitPosition(position), wct);
} else {
position = getMainStagePosition();
}
@@ -923,7 +991,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@SplitPosition
int getMainStagePosition() {
- return SplitLayout.reversePosition(mSideStagePosition);
+ return reverseSplitPosition(mSideStagePosition);
}
int getTaskId(@SplitPosition int splitPosition) {
@@ -950,7 +1018,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.splitSwitching(t, topLeftStage.mRootLeash, bottomRightStage.mRootLeash,
insets -> {
WindowContainerTransaction wct = new WindowContainerTransaction();
- setSideStagePosition(SplitLayout.reversePosition(mSideStagePosition), wct);
+ setSideStagePosition(reverseSplitPosition(mSideStagePosition), wct);
mSyncQueue.queue(wct);
mSyncQueue.runInSync(st -> {
updateSurfaceBounds(mSplitLayout, st, false /* applyResizingOffset */);
@@ -1694,12 +1762,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
- boolean isValidToEnterSplitScreen(@NonNull ActivityManager.RunningTaskInfo taskInfo) {
- return taskInfo.supportsMultiWindow
- && ArrayUtils.contains(CONTROLLED_ACTIVITY_TYPES, taskInfo.getActivityType())
- && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode());
- }
-
@Override
public void onSnappedToDismiss(boolean bottomOrRight, int reason) {
final boolean mainStageToTop =
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index ea3af9d96aa4..d0e26019f9bf 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -27,8 +27,6 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSIT
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -201,7 +199,6 @@ public class SplitScreenControllerTests extends ShellTestCase {
ActivityManager.RunningTaskInfo topRunningTask =
createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, startIntent);
doReturn(topRunningTask).when(mRecentTasks).getTopRunningTask();
- doReturn(true).when(mStageCoordinator).isValidToEnterSplitScreen(any());
mSplitScreenController.startIntent(pendingIntent, null, SPLIT_POSITION_TOP_OR_LEFT, null);
@@ -222,7 +219,6 @@ public class SplitScreenControllerTests extends ShellTestCase {
ActivityManager.RunningTaskInfo topRunningTask =
createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, startIntent);
doReturn(topRunningTask).when(mRecentTasks).getTopRunningTask();
- doReturn(true).when(mStageCoordinator).isValidToEnterSplitScreen(any());
// Put the same component into a task in the background
ActivityManager.RecentTaskInfo sameTaskInfo = new ActivityManager.RecentTaskInfo();
doReturn(sameTaskInfo).when(mRecentTasks).findTaskInBackground(any());
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
index 4b73e948e1e6..b92729dab7c0 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -24,10 +24,6 @@ import androidx.compose.runtime.ProvidedValue
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.remember
import com.android.settingslib.spa.framework.compose.LocalNavController
-import com.android.settingslib.spa.framework.util.genEntryId
-
-private const val INJECT_ENTRY_NAME = "INJECT"
-private const val ROOT_ENTRY_NAME = "ROOT"
interface EntryData {
val pageId: String?
@@ -164,143 +160,3 @@ data class SettingsEntry(
}
}
}
-
-/**
- * The helper to build a Settings Entry instance.
- */
-class SettingsEntryBuilder(private val name: String, private val owner: SettingsPage) {
- private var displayName = name
- private var fromPage: SettingsPage? = null
- private var toPage: SettingsPage? = null
-
- // Attributes
- private var isAllowSearch: Boolean = false
- private var isSearchDataDynamic: Boolean = false
- private var hasMutableStatus: Boolean = false
- private var hasSliceSupport: Boolean = false
-
- // Functions
- private var uiLayoutFn: UiLayerRenderer = { }
- private var statusDataFn: StatusDataGetter = { null }
- private var searchDataFn: SearchDataGetter = { null }
- private var sliceDataFn: SliceDataGetter = { _: Uri, _: Bundle? -> null }
-
- fun build(): SettingsEntry {
- val page = fromPage ?: owner
- val isEnabled = page.isEnabled()
- return SettingsEntry(
- id = genEntryId(name, owner, fromPage, toPage),
- name = name,
- owner = owner,
- displayName = displayName,
-
- // linking data
- fromPage = fromPage,
- toPage = toPage,
-
- // attributes
- // TODO: set isEnabled & (isAllowSearch, hasSliceSupport) separately
- isAllowSearch = isEnabled && isAllowSearch,
- isSearchDataDynamic = isSearchDataDynamic,
- hasMutableStatus = hasMutableStatus,
- hasSliceSupport = isEnabled && hasSliceSupport,
-
- // functions
- statusDataImpl = statusDataFn,
- searchDataImpl = searchDataFn,
- sliceDataImpl = sliceDataFn,
- uiLayoutImpl = uiLayoutFn,
- )
- }
-
- fun setDisplayName(displayName: String): SettingsEntryBuilder {
- this.displayName = displayName
- return this
- }
-
- fun setLink(
- fromPage: SettingsPage? = null,
- toPage: SettingsPage? = null
- ): SettingsEntryBuilder {
- if (fromPage != null) this.fromPage = fromPage
- if (toPage != null) this.toPage = toPage
- return this
- }
-
- fun setIsSearchDataDynamic(isDynamic: Boolean): SettingsEntryBuilder {
- this.isSearchDataDynamic = isDynamic
- return this
- }
-
- fun setHasMutableStatus(hasMutableStatus: Boolean): SettingsEntryBuilder {
- this.hasMutableStatus = hasMutableStatus
- return this
- }
-
- fun setMacro(fn: (arguments: Bundle?) -> EntryMacro): SettingsEntryBuilder {
- setStatusDataFn { fn(it).getStatusData() }
- setSearchDataFn { fn(it).getSearchData() }
- setUiLayoutFn {
- val macro = remember { fn(it) }
- macro.UiLayout()
- }
- return this
- }
-
- fun setStatusDataFn(fn: StatusDataGetter): SettingsEntryBuilder {
- this.statusDataFn = fn
- return this
- }
-
- fun setSearchDataFn(fn: SearchDataGetter): SettingsEntryBuilder {
- this.searchDataFn = fn
- this.isAllowSearch = true
- return this
- }
-
- fun clearSearchDataFn(): SettingsEntryBuilder {
- this.searchDataFn = { null }
- this.isAllowSearch = false
- return this
- }
-
- fun setSliceDataFn(fn: SliceDataGetter): SettingsEntryBuilder {
- this.sliceDataFn = fn
- this.hasSliceSupport = true
- return this
- }
-
- fun setUiLayoutFn(fn: UiLayerRenderer): SettingsEntryBuilder {
- this.uiLayoutFn = fn
- return this
- }
-
- companion object {
- fun create(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
- return SettingsEntryBuilder(entryName, owner)
- }
-
- fun createLinkFrom(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
- return create(entryName, owner).setLink(fromPage = owner)
- }
-
- fun createLinkTo(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
- return create(entryName, owner).setLink(toPage = owner)
- }
-
- fun create(owner: SettingsPage, entryName: String, displayName: String? = null):
- SettingsEntryBuilder {
- return SettingsEntryBuilder(entryName, owner).setDisplayName(displayName ?: entryName)
- }
-
- fun createInject(owner: SettingsPage, displayName: String? = null): SettingsEntryBuilder {
- val name = displayName ?: "${INJECT_ENTRY_NAME}_${owner.displayName}"
- return createLinkTo(INJECT_ENTRY_NAME, owner).setDisplayName(name)
- }
-
- fun createRoot(owner: SettingsPage, displayName: String? = null): SettingsEntryBuilder {
- val name = displayName ?: "${ROOT_ENTRY_NAME}_${owner.displayName}"
- return createLinkTo(ROOT_ENTRY_NAME, owner).setDisplayName(name)
- }
- }
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
new file mode 100644
index 000000000000..67f9ea52a40d
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryBuilder.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2023 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.settingslib.spa.framework.common
+
+import android.net.Uri
+import android.os.Bundle
+import androidx.compose.runtime.remember
+import com.android.settingslib.spa.framework.util.genEntryId
+
+private const val INJECT_ENTRY_NAME = "INJECT"
+private const val ROOT_ENTRY_NAME = "ROOT"
+
+/**
+ * The helper to build a Settings Entry instance.
+ */
+class SettingsEntryBuilder(private val name: String, private val owner: SettingsPage) {
+ private var displayName = name
+ private var fromPage: SettingsPage? = null
+ private var toPage: SettingsPage? = null
+
+ // Attributes
+ private var isAllowSearch: Boolean = false
+ private var isSearchDataDynamic: Boolean = false
+ private var hasMutableStatus: Boolean = false
+ private var hasSliceSupport: Boolean = false
+
+ // Functions
+ private var uiLayoutFn: UiLayerRenderer = { }
+ private var statusDataFn: StatusDataGetter = { null }
+ private var searchDataFn: SearchDataGetter = { null }
+ private var sliceDataFn: SliceDataGetter = { _: Uri, _: Bundle? -> null }
+
+ fun build(): SettingsEntry {
+ val page = fromPage ?: owner
+ val isEnabled = page.isEnabled()
+ return SettingsEntry(
+ id = genEntryId(name, owner, fromPage, toPage),
+ name = name,
+ owner = owner,
+ displayName = displayName,
+
+ // linking data
+ fromPage = fromPage,
+ toPage = toPage,
+
+ // attributes
+ // TODO: set isEnabled & (isAllowSearch, hasSliceSupport) separately
+ isAllowSearch = isEnabled && isAllowSearch,
+ isSearchDataDynamic = isSearchDataDynamic,
+ hasMutableStatus = hasMutableStatus,
+ hasSliceSupport = isEnabled && hasSliceSupport,
+
+ // functions
+ statusDataImpl = statusDataFn,
+ searchDataImpl = searchDataFn,
+ sliceDataImpl = sliceDataFn,
+ uiLayoutImpl = uiLayoutFn,
+ )
+ }
+
+ fun setDisplayName(displayName: String): SettingsEntryBuilder {
+ this.displayName = displayName
+ return this
+ }
+
+ fun setLink(
+ fromPage: SettingsPage? = null,
+ toPage: SettingsPage? = null
+ ): SettingsEntryBuilder {
+ if (fromPage != null) this.fromPage = fromPage
+ if (toPage != null) this.toPage = toPage
+ return this
+ }
+
+ fun setIsSearchDataDynamic(isDynamic: Boolean): SettingsEntryBuilder {
+ this.isSearchDataDynamic = isDynamic
+ return this
+ }
+
+ fun setHasMutableStatus(hasMutableStatus: Boolean): SettingsEntryBuilder {
+ this.hasMutableStatus = hasMutableStatus
+ return this
+ }
+
+ fun setMacro(fn: (arguments: Bundle?) -> EntryMacro): SettingsEntryBuilder {
+ setStatusDataFn { fn(it).getStatusData() }
+ setSearchDataFn { fn(it).getSearchData() }
+ setUiLayoutFn {
+ val macro = remember { fn(it) }
+ macro.UiLayout()
+ }
+ return this
+ }
+
+ fun setStatusDataFn(fn: StatusDataGetter): SettingsEntryBuilder {
+ this.statusDataFn = fn
+ return this
+ }
+
+ fun setSearchDataFn(fn: SearchDataGetter): SettingsEntryBuilder {
+ this.searchDataFn = fn
+ this.isAllowSearch = true
+ return this
+ }
+
+ fun clearSearchDataFn(): SettingsEntryBuilder {
+ this.searchDataFn = { null }
+ this.isAllowSearch = false
+ return this
+ }
+
+ fun setSliceDataFn(fn: SliceDataGetter): SettingsEntryBuilder {
+ this.sliceDataFn = fn
+ this.hasSliceSupport = true
+ return this
+ }
+
+ fun setUiLayoutFn(fn: UiLayerRenderer): SettingsEntryBuilder {
+ this.uiLayoutFn = fn
+ return this
+ }
+
+ companion object {
+ fun create(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
+ return SettingsEntryBuilder(entryName, owner)
+ }
+
+ fun createLinkFrom(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
+ return create(entryName, owner).setLink(fromPage = owner)
+ }
+
+ fun createLinkTo(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
+ return create(entryName, owner).setLink(toPage = owner)
+ }
+
+ fun create(owner: SettingsPage, entryName: String, displayName: String? = null):
+ SettingsEntryBuilder {
+ return SettingsEntryBuilder(entryName, owner).setDisplayName(displayName ?: entryName)
+ }
+
+ fun createInject(owner: SettingsPage, displayName: String? = null): SettingsEntryBuilder {
+ val name = displayName ?: "${INJECT_ENTRY_NAME}_${owner.displayName}"
+ return createLinkTo(INJECT_ENTRY_NAME, owner).setDisplayName(name)
+ }
+
+ fun createRoot(owner: SettingsPage, displayName: String? = null): SettingsEntryBuilder {
+ val name = displayName ?: "${ROOT_ENTRY_NAME}_${owner.displayName}"
+ return createLinkTo(ROOT_ENTRY_NAME, owner).setDisplayName(name)
+ }
+ }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
index 14dc7857dbc7..7aeefd23d116 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
@@ -30,14 +30,10 @@ data class SettingsPageWithEntry(
val injectEntry: SettingsEntry,
)
-private fun SettingsPage.getTitle(sppRepository: SettingsPageProviderRepository): String {
- return sppRepository.getProviderOrNull(sppName)!!.getTitle(arguments)
-}
-
/**
* The repository to maintain all Settings entries
*/
-class SettingsEntryRepository(private val sppRepository: SettingsPageProviderRepository) {
+class SettingsEntryRepository(sppRepository: SettingsPageProviderRepository) {
// Map of entry unique Id to entry
private val entryMap: Map<String, SettingsEntry>
@@ -123,7 +119,7 @@ class SettingsEntryRepository(private val sppRepository: SettingsPageProviderRep
if (it.toPage == null)
defaultTitle
else {
- it.toPage.getTitle(sppRepository)
+ it.toPage.getTitle()
}
}
}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt
index c810648524b9..724588f794b4 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt
@@ -81,6 +81,10 @@ data class SettingsPage(
return getPageProvider(sppName)?.isEnabled(arguments) ?: false
}
+ fun getTitle(): String {
+ return getPageProvider(sppName)?.getTitle(arguments) ?: ""
+ }
+
@Composable
fun UiLayout() {
getPageProvider(sppName)?.Page(arguments)
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
index 730aa8f95e63..379b9a7db09b 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
@@ -113,6 +113,7 @@ class SettingsEntryRepositoryTest {
@Test
fun testGetEntryPath() {
+ SpaEnvironmentFactory.reset(spaEnvironment)
assertThat(
entryRepository.getEntryPathWithDisplayName(
genEntryId("Layer2Entry1", SppLayer2.createSettingsPage())
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 5eb7831692ab..d02eee076bc2 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -525,7 +525,7 @@ object Flags {
// 1500 - chooser aka sharesheet
// TODO(b/254512507): Tracking Bug
- val CHOOSER_UNBUNDLED = releasedFlag(1500, "chooser_unbundled")
+ val CHOOSER_UNBUNDLED = unreleasedFlag(1500, "chooser_unbundled", teamfood = true)
// TODO(b/266983432) Tracking Bug
val SHARESHEET_CUSTOM_ACTIONS =
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 35423f4c4140..d5d73258bb08 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -30,7 +30,6 @@ import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
-import static android.view.InsetsState.containsType;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
@@ -85,7 +84,6 @@ import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.InsetsFrameProvider;
-import android.view.InsetsState.InternalInsetsType;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
@@ -97,6 +95,7 @@ import android.view.ViewRootImpl.SurfaceChangedCallback;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
+import android.view.WindowInsets;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -1150,12 +1149,11 @@ public class NavigationBar extends ViewController<NavigationBarView> implements
}
@Override
- public void showTransient(int displayId, @InternalInsetsType int[] types,
- boolean isGestureOnSystemBar) {
+ public void showTransient(int displayId, @InsetsType int types, boolean isGestureOnSystemBar) {
if (displayId != mDisplayId) {
return;
}
- if (!containsType(types, ITYPE_NAVIGATION_BAR)) {
+ if ((types & WindowInsets.Type.navigationBars()) == 0) {
return;
}
if (!mTransientShown) {
@@ -1166,11 +1164,11 @@ public class NavigationBar extends ViewController<NavigationBarView> implements
}
@Override
- public void abortTransient(int displayId, @InternalInsetsType int[] types) {
+ public void abortTransient(int displayId, @InsetsType int types) {
if (displayId != mDisplayId) {
return;
}
- if (!containsType(types, ITYPE_NAVIGATION_BAR)) {
+ if ((types & WindowInsets.Type.navigationBars()) == 0) {
return;
}
clearTransient();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index f3712e66e330..c3d736917b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -20,8 +20,6 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
-import static android.view.InsetsState.containsType;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -41,7 +39,6 @@ import static com.android.systemui.statusbar.phone.BarTransitions.TransitionMode
import android.app.StatusBarManager;
import android.app.StatusBarManager.WindowVisibleState;
-import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
@@ -52,6 +49,7 @@ import android.os.RemoteException;
import android.util.Log;
import android.view.Display;
import android.view.View;
+import android.view.WindowInsets;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -68,7 +66,6 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.shared.recents.utilities.Utilities;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -401,11 +398,11 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
}
@Override
- public void showTransient(int displayId, int[] types, boolean isGestureOnSystemBar) {
+ public void showTransient(int displayId, @InsetsType int types, boolean isGestureOnSystemBar) {
if (displayId != mDisplayId) {
return;
}
- if (!containsType(types, ITYPE_EXTRA_NAVIGATION_BAR)) {
+ if ((types & WindowInsets.Type.navigationBars()) == 0) {
return;
}
if (!mTaskbarTransientShowing) {
@@ -415,11 +412,11 @@ public class TaskbarDelegate implements CommandQueue.Callbacks,
}
@Override
- public void abortTransient(int displayId, int[] types) {
+ public void abortTransient(int displayId, @InsetsType int types) {
if (displayId != mDisplayId) {
return;
}
- if (!containsType(types, ITYPE_EXTRA_NAVIGATION_BAR)) {
+ if ((types & WindowInsets.Type.navigationBars()) == 0) {
return;
}
clearTransient();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 3aaad87b8eab..2cf1f53b4499 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -53,7 +53,6 @@ import android.os.Process;
import android.os.RemoteException;
import android.util.Pair;
import android.util.SparseArray;
-import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -371,22 +370,22 @@ public class CommandQueue extends IStatusBar.Stub implements
String packageName, LetterboxDetails[] letterboxDetails) { }
/**
- * @see IStatusBar#showTransient(int, int[], boolean).
+ * @see IStatusBar#showTransient(int, int, boolean).
*/
- default void showTransient(int displayId, @InternalInsetsType int[] types) { }
+ default void showTransient(int displayId, @InsetsType int types) { }
/**
- * @see IStatusBar#showTransient(int, int[], boolean).
+ * @see IStatusBar#showTransient(int, int, boolean).
*/
- default void showTransient(int displayId, @InternalInsetsType int[] types,
+ default void showTransient(int displayId, @InsetsType int types,
boolean isGestureOnSystemBar) {
showTransient(displayId, types);
}
/**
- * @see IStatusBar#abortTransient(int, int[]).
+ * @see IStatusBar#abortTransient(int, int).
*/
- default void abortTransient(int displayId, @InternalInsetsType int[] types) { }
+ default void abortTransient(int displayId, @InsetsType int types) { }
/**
* Called to notify System UI that a warning about the device going to sleep
@@ -1131,17 +1130,23 @@ public class CommandQueue extends IStatusBar.Stub implements
}
@Override
- public void showTransient(int displayId, int[] types, boolean isGestureOnSystemBar) {
+ public void showTransient(int displayId, int types, boolean isGestureOnSystemBar) {
synchronized (mLock) {
- mHandler.obtainMessage(MSG_SHOW_TRANSIENT, displayId, isGestureOnSystemBar ? 1 : 0,
- types).sendToTarget();
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = displayId;
+ args.argi2 = types;
+ args.argi3 = isGestureOnSystemBar ? 1 : 0;
+ mHandler.obtainMessage(MSG_SHOW_TRANSIENT, args).sendToTarget();
}
}
@Override
- public void abortTransient(int displayId, int[] types) {
+ public void abortTransient(int displayId, int types) {
synchronized (mLock) {
- mHandler.obtainMessage(MSG_ABORT_TRANSIENT, displayId, 0, types).sendToTarget();
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = displayId;
+ args.argi2 = types;
+ mHandler.obtainMessage(MSG_ABORT_TRANSIENT, args).sendToTarget();
}
}
@@ -1644,17 +1649,21 @@ public class CommandQueue extends IStatusBar.Stub implements
args.recycle();
break;
case MSG_SHOW_TRANSIENT: {
- final int displayId = msg.arg1;
- final int[] types = (int[]) msg.obj;
- final boolean isGestureOnSystemBar = msg.arg2 != 0;
+ args = (SomeArgs) msg.obj;
+ final int displayId = args.argi1;
+ final int types = args.argi2;
+ final boolean isGestureOnSystemBar = args.argi3 != 0;
+ args.recycle();
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).showTransient(displayId, types, isGestureOnSystemBar);
}
break;
}
case MSG_ABORT_TRANSIENT: {
- final int displayId = msg.arg1;
- final int[] types = (int[]) msg.obj;
+ args = (SomeArgs) msg.obj;
+ final int displayId = args.argi1;
+ final int types = args.argi2;
+ args.recycle();
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).abortTransient(displayId, types);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 856d7dedb4eb..fecaa3a0caf5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -16,9 +16,6 @@
package com.android.systemui.statusbar.phone;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.containsType;
-
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
@@ -36,8 +33,8 @@ import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.Log;
import android.util.Slog;
-import android.view.InsetsState.InternalInsetsType;
import android.view.KeyEvent;
+import android.view.WindowInsets;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -168,11 +165,11 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
}
@Override
- public void abortTransient(int displayId, @InternalInsetsType int[] types) {
+ public void abortTransient(int displayId, @InsetsType int types) {
if (displayId != mDisplayId) {
return;
}
- if (!containsType(types, ITYPE_STATUS_BAR)) {
+ if ((types & WindowInsets.Type.statusBars()) == 0) {
return;
}
mCentralSurfaces.clearTransient();
@@ -489,12 +486,11 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba
}
@Override
- public void showTransient(int displayId, @InternalInsetsType int[] types,
- boolean isGestureOnSystemBar) {
+ public void showTransient(int displayId, @InsetsType int types, boolean isGestureOnSystemBar) {
if (displayId != mDisplayId) {
return;
}
- if (!containsType(types, ITYPE_STATUS_BAR)) {
+ if ((types & WindowInsets.Type.statusBars()) == 0) {
return;
}
mCentralSurfaces.showTransientUnchecked();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index e595ddf46a89..1966a6657acb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -21,8 +21,6 @@ import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.containsType;
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS;
@@ -100,6 +98,7 @@ import android.view.ThreadedRenderer;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
+import android.view.WindowInsets;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
@@ -943,7 +942,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces {
// Set up the initial notification state. This needs to happen before CommandQueue.disable()
setUpPresenter();
- if (containsType(result.mTransientBarTypes, ITYPE_STATUS_BAR)) {
+ if ((result.mTransientBarTypes & WindowInsets.Type.statusBars()) != 0) {
showTransientUnchecked();
}
mCommandQueueCallbacks.onSystemBarAttributesChanged(mDisplayId, result.mAppearance,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt
index babbe451dd6a..32edf8f23aed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt
@@ -11,7 +11,6 @@ import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flag
import com.android.systemui.flags.FlagListenable
import com.android.systemui.flags.Flags
-import com.android.systemui.flags.ReleasedFlag
import com.android.systemui.flags.UnreleasedFlag
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.any
@@ -103,7 +102,7 @@ class ChooserSelectorTest : SysuiTestCase() {
@Test
fun initialize_enablesUnbundledChooser_whenFlagEnabled() {
// Arrange
- setFlagMock(true)
+ whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true)
// Act
chooserSelector.start()
@@ -119,7 +118,7 @@ class ChooserSelectorTest : SysuiTestCase() {
@Test
fun initialize_disablesUnbundledChooser_whenFlagDisabled() {
// Arrange
- setFlagMock(false)
+ whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
// Act
chooserSelector.start()
@@ -135,7 +134,7 @@ class ChooserSelectorTest : SysuiTestCase() {
@Test
fun enablesUnbundledChooser_whenFlagBecomesEnabled() {
// Arrange
- setFlagMock(false)
+ whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
chooserSelector.start()
verify(mockFeatureFlags).addListener(
eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED),
@@ -148,7 +147,7 @@ class ChooserSelectorTest : SysuiTestCase() {
)
// Act
- setFlagMock(true)
+ whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true)
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.name))
// Assert
@@ -162,7 +161,7 @@ class ChooserSelectorTest : SysuiTestCase() {
@Test
fun disablesUnbundledChooser_whenFlagBecomesDisabled() {
// Arrange
- setFlagMock(true)
+ whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true)
chooserSelector.start()
verify(mockFeatureFlags).addListener(
eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED),
@@ -175,7 +174,7 @@ class ChooserSelectorTest : SysuiTestCase() {
)
// Act
- setFlagMock(false)
+ whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.name))
// Assert
@@ -189,7 +188,7 @@ class ChooserSelectorTest : SysuiTestCase() {
@Test
fun doesNothing_whenAnotherFlagChanges() {
// Arrange
- setFlagMock(false)
+ whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
chooserSelector.start()
verify(mockFeatureFlags).addListener(
eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED),
@@ -198,17 +197,13 @@ class ChooserSelectorTest : SysuiTestCase() {
clearInvocations(mockPackageManager)
// Act
+ whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
flagListener.value.onFlagChanged(TestFlagEvent("other flag"))
// Assert
verifyZeroInteractions(mockPackageManager)
}
- private fun setFlagMock(enabled: Boolean) {
- whenever(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(enabled)
- whenever(mockFeatureFlags.isEnabled(any<ReleasedFlag>())).thenReturn(enabled)
- }
-
private class TestFlagEvent(override val flagName: String) : FlagListenable.FlagEvent {
override fun requestNoRestart() {}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index b1ca1c02f6da..f581154f66c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -18,8 +18,6 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
import static android.inputmethodservice.InputMethodService.IME_INVISIBLE;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -158,7 +156,7 @@ public class CommandQueueTest extends SysuiTestCase {
@Test
public void testShowTransient() {
- int[] types = new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR};
+ int types = WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars();
mCommandQueue.showTransient(DEFAULT_DISPLAY, types, true /* isGestureOnSystemBar */);
waitForIdleSync();
verify(mCallbacks).showTransient(eq(DEFAULT_DISPLAY), eq(types), eq(true));
@@ -166,7 +164,7 @@ public class CommandQueueTest extends SysuiTestCase {
@Test
public void testShowTransientForSecondaryDisplay() {
- int[] types = new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR};
+ int types = WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars();
mCommandQueue.showTransient(SECONDARY_DISPLAY, types, true /* isGestureOnSystemBar */);
waitForIdleSync();
verify(mCallbacks).showTransient(eq(SECONDARY_DISPLAY), eq(types), eq(true));
@@ -174,7 +172,7 @@ public class CommandQueueTest extends SysuiTestCase {
@Test
public void testAbortTransient() {
- int[] types = new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR};
+ int types = WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars();
mCommandQueue.abortTransient(DEFAULT_DISPLAY, types);
waitForIdleSync();
verify(mCallbacks).abortTransient(eq(DEFAULT_DISPLAY), eq(types));
@@ -182,7 +180,7 @@ public class CommandQueueTest extends SysuiTestCase {
@Test
public void testAbortTransientForSecondaryDisplay() {
- int[] types = new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR};
+ int types = WindowInsets.Type.statusBars() | WindowInsets.Type.navigationBars();
mCommandQueue.abortTransient(SECONDARY_DISPLAY, types);
waitForIdleSync();
verify(mCallbacks).abortTransient(eq(SECONDARY_DISPLAY), eq(types));
diff --git a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
index 969a174f49c7..0b5c1c171354 100644
--- a/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
+++ b/services/core/java/com/android/server/biometrics/sensors/SensorOverlays.java
@@ -150,6 +150,13 @@ public final class SensorOverlays {
}
/**
+ * Returns if the sensor is side fps.
+ */
+ public boolean isSfps() {
+ return mSidefpsController.isPresent();
+ }
+
+ /**
* Consumer for a biometric overlay controller.
*
* This behaves like a normal {@link Consumer} except that it will trap and log
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index a90679e755cf..932c0b4948a0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -236,8 +236,14 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession>
@Override
public void onError(int errorCode, int vendorCode) {
- super.onError(errorCode, vendorCode);
-
+ if (errorCode == BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR
+ && vendorCode == BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED
+ && mSensorOverlays.isSfps()) {
+ super.onError(BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED,
+ 0 /* vendorCode */);
+ } else {
+ super.onError(errorCode, vendorCode);
+ }
if (errorCode == BiometricFingerprintConstants.FINGERPRINT_ERROR_BAD_CALIBRATION) {
BiometricNotificationUtils.showBadCalibrationNotification(getContext());
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 513b3e3e6e86..cf54662dfa7d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -146,7 +146,14 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps
}
});
mCallback.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH);
- super.onAcquired(acquiredInfo, vendorCode);
+ if (acquiredInfo == BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR
+ && vendorCode == BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED
+ && mSensorOverlays.isSfps()) {
+ super.onAcquired(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED,
+ 0 /* vendorCode */);
+ } else {
+ super.onAcquired(acquiredInfo, vendorCode);
+ }
}
@Override
@@ -274,8 +281,5 @@ class FingerprintEnrollClient extends EnrollClient<AidlSession> implements Udfps
}
@Override
- public void onPowerPressed() {
- onAcquired(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED,
- 0 /* vendorCode */);
- }
+ public void onPowerPressed() { }
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index c5bcddc06298..6b9be2545c73 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -1116,12 +1116,16 @@ public class LauncherAppsService extends SystemService {
// Flag for bubble
ActivityOptions options = ActivityOptions.fromBundle(startActivityOptions);
- if (options != null && options.isApplyActivityFlagsForBubbles()) {
- // Flag for bubble to make behaviour match documentLaunchMode=always.
- intents[0].addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
- intents[0].addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ if (options != null) {
+ if (options.isApplyActivityFlagsForBubbles()) {
+ // Flag for bubble to make behaviour match documentLaunchMode=always.
+ intents[0].addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
+ intents[0].addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+ if (options.isApplyMultipleTaskFlagForShortcut()) {
+ intents[0].addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
}
-
intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intents[0].setSourceBounds(sourceBounds);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 5521384bb169..ec052ecd20f2 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -21,7 +21,6 @@ import android.app.ITransientNotificationCallback;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
import android.os.Bundle;
import android.os.IBinder;
-import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsController.Appearance;
import android.view.WindowInsetsController.Behavior;
@@ -162,11 +161,10 @@ public interface StatusBarManagerInternal {
LetterboxDetails[] letterboxDetails);
/** @see com.android.internal.statusbar.IStatusBar#showTransient */
- void showTransient(int displayId, @InternalInsetsType int[] types,
- boolean isGestureOnSystemBar);
+ void showTransient(int displayId, @InsetsType int types, boolean isGestureOnSystemBar);
/** @see com.android.internal.statusbar.IStatusBar#abortTransient */
- void abortTransient(int displayId, @InternalInsetsType int[] types);
+ void abortTransient(int displayId, @InsetsType int types);
/**
* @see com.android.internal.statusbar.IStatusBar#showToast(String, IBinder, CharSequence,
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 83f4805aca58..4489ba94235c 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -79,12 +79,10 @@ import android.service.notification.NotificationStats;
import android.service.quicksettings.TileService;
import android.text.TextUtils;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsets;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsController.Appearance;
@@ -645,7 +643,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
}
@Override
- public void showTransient(int displayId, @InternalInsetsType int[] types,
+ public void showTransient(int displayId, @InsetsType int types,
boolean isGestureOnSystemBar) {
getUiState(displayId).showTransient(types);
if (mBar != null) {
@@ -656,7 +654,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
}
@Override
- public void abortTransient(int displayId, @InternalInsetsType int[] types) {
+ public void abortTransient(int displayId, @InsetsType int types) {
getUiState(displayId).clearTransient(types);
if (mBar != null) {
try {
@@ -1258,7 +1256,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
private static class UiState {
private @Appearance int mAppearance = 0;
private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0];
- private final ArraySet<Integer> mTransientBarTypes = new ArraySet<>();
+ private @InsetsType int mTransientBarTypes;
private boolean mNavbarColorManagedByIme = false;
private @Behavior int mBehavior;
private @InsetsType int mRequestedVisibleTypes = WindowInsets.Type.defaultVisible();
@@ -1285,16 +1283,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
mLetterboxDetails = letterboxDetails;
}
- private void showTransient(@InternalInsetsType int[] types) {
- for (int type : types) {
- mTransientBarTypes.add(type);
- }
+ private void showTransient(@InsetsType int types) {
+ mTransientBarTypes |= types;
}
- private void clearTransient(@InternalInsetsType int[] types) {
- for (int type : types) {
- mTransientBarTypes.remove(type);
- }
+ private void clearTransient(@InsetsType int types) {
+ mTransientBarTypes &= ~types;
}
private int getDisabled1() {
@@ -1410,16 +1404,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
// TODO(b/118592525): Currently, status bar only works on the default display.
// Make it aware of multi-display if needed.
final UiState state = mDisplayUiState.get(DEFAULT_DISPLAY);
- final int[] transientBarTypes = new int[state.mTransientBarTypes.size()];
- for (int i = 0; i < transientBarTypes.length; i++) {
- transientBarTypes[i] = state.mTransientBarTypes.valueAt(i);
- }
return new RegisterStatusBarResult(icons, gatherDisableActionsLocked(mCurrentUserId, 1),
state.mAppearance, state.mAppearanceRegions, state.mImeWindowVis,
state.mImeBackDisposition, state.mShowImeSwitcher,
gatherDisableActionsLocked(mCurrentUserId, 2), state.mImeToken,
state.mNavbarColorManagedByIme, state.mBehavior, state.mRequestedVisibleTypes,
- state.mPackageName, transientBarTypes, state.mLetterboxDetails);
+ state.mPackageName, state.mTransientBarTypes, state.mLetterboxDetails);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 50eb356a0b37..c37a3d7f43ee 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1033,10 +1033,33 @@ class ActivityStarter {
return err;
}
- boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
- requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
- request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord,
- resultRootTask);
+ boolean abort;
+ try {
+ abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
+ requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
+ request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord,
+ resultRootTask);
+ } catch (SecurityException e) {
+ // Return activity not found for the explicit intent if the caller can't see the target
+ // to prevent the disclosure of package existence.
+ final Intent originalIntent = request.ephemeralIntent;
+ if (originalIntent != null && (originalIntent.getComponent() != null
+ || originalIntent.getPackage() != null)) {
+ final String targetPackageName = originalIntent.getComponent() != null
+ ? originalIntent.getComponent().getPackageName()
+ : originalIntent.getPackage();
+ if (mService.getPackageManagerInternalLocked()
+ .filterAppAccess(targetPackageName, callingUid, userId)) {
+ if (resultRecord != null) {
+ resultRecord.sendResult(INVALID_UID, resultWho, requestCode,
+ RESULT_CANCELED, null /* data */, null /* dataGrants */);
+ }
+ SafeActivityOptions.abort(options);
+ return ActivityManager.START_CLASS_NOT_FOUND;
+ }
+ }
+ throw e;
+ }
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index e87680ac5a16..7c12dbc7964b 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -171,9 +171,8 @@ public class DisplayPolicy {
/** Use the transit animation in style resource (see {@link #selectAnimation}). */
static final int ANIMATION_STYLEABLE = 0;
- private static final int[] SHOW_TYPES_FOR_SWIPE = {ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR,
- ITYPE_CLIMATE_BAR, ITYPE_EXTRA_NAVIGATION_BAR};
- private static final int[] SHOW_TYPES_FOR_PANIC = {ITYPE_NAVIGATION_BAR};
+ private static final int SHOW_TYPES_FOR_SWIPE = Type.statusBars() | Type.navigationBars();
+ private static final int SHOW_TYPES_FOR_PANIC = Type.navigationBars();
private final WindowManagerService mService;
private final Context mContext;
@@ -251,7 +250,7 @@ public class DisplayPolicy {
private boolean mIsFreeformWindowOverlappingWithNavBar;
- private boolean mLastImmersiveMode;
+ private boolean mIsImmersiveMode;
// The windows we were told about in focusChanged.
private WindowState mFocusedWindow;
@@ -2171,14 +2170,27 @@ public class DisplayPolicy {
appearance = configureNavBarOpacity(appearance, multiWindowTaskVisible,
freeformRootTaskVisible);
+ // Show immersive mode confirmation if needed.
+ final boolean wasImmersiveMode = mIsImmersiveMode;
+ final boolean isImmersiveMode = isImmersiveMode(win);
+ if (wasImmersiveMode != isImmersiveMode) {
+ mIsImmersiveMode = isImmersiveMode;
+ // The immersive confirmation window should be attached to the immersive window root.
+ final RootDisplayArea root = win.getRootDisplayArea();
+ final int rootDisplayAreaId = root == null ? FEATURE_UNDEFINED : root.mFeatureId;
+ mImmersiveModeConfirmation.immersiveModeChangedLw(rootDisplayAreaId, isImmersiveMode,
+ mService.mPolicy.isUserSetupComplete(),
+ isNavBarEmpty(disableFlags));
+ }
+
+ // Show transient bars for panic if needed.
final boolean requestHideNavBar = !win.isRequestedVisible(Type.navigationBars());
final long now = SystemClock.uptimeMillis();
final boolean pendingPanic = mPendingPanicGestureUptime != 0
&& now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
final DisplayPolicy defaultDisplayPolicy =
mService.getDefaultDisplayContentLocked().getDisplayPolicy();
- if (pendingPanic && requestHideNavBar && win != mNotificationShade
- && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)
+ if (pendingPanic && requestHideNavBar && isImmersiveMode
// TODO (b/111955725): Show keyguard presentation on all external displays
&& defaultDisplayPolicy.isKeyguardDrawComplete()) {
// The user performed the panic gesture recently, we're about to hide the bars,
@@ -2190,19 +2202,6 @@ public class DisplayPolicy {
}
}
- // update navigation bar
- boolean oldImmersiveMode = mLastImmersiveMode;
- boolean newImmersiveMode = isImmersiveMode(win);
- if (oldImmersiveMode != newImmersiveMode) {
- mLastImmersiveMode = newImmersiveMode;
- // The immersive confirmation window should be attached to the immersive window root.
- final RootDisplayArea root = win.getRootDisplayArea();
- final int rootDisplayAreaId = root == null ? FEATURE_UNDEFINED : root.mFeatureId;
- mImmersiveModeConfirmation.immersiveModeChangedLw(rootDisplayAreaId, newImmersiveMode,
- mService.mPolicy.isUserSetupComplete(),
- isNavBarEmpty(disableFlags));
- }
-
return appearance;
}
@@ -2324,18 +2323,10 @@ public class DisplayPolicy {
if (win == null) {
return false;
}
- return getNavigationBar() != null
- && canHideNavigationBar()
- && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)
- && win != getNotificationShade()
- && !win.isActivityTypeDream();
- }
-
- /**
- * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
- */
- private boolean canHideNavigationBar() {
- return hasNavigationBar();
+ if (win == getNotificationShade() || win.isActivityTypeDream()) {
+ return false;
+ }
+ return getInsetsPolicy().hasHiddenSources(Type.navigationBars());
}
private static boolean isNavBarEmpty(int systemUiFlags) {
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index bd821134f9b7..f5d29ed54921 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -26,8 +26,6 @@ import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
import static android.view.InsetsSource.ID_IME;
-import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
@@ -42,7 +40,6 @@ import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.res.Resources;
import android.util.ArrayMap;
-import android.util.IntArray;
import android.util.SparseArray;
import android.view.InsetsAnimationControlCallbacks;
import android.view.InsetsAnimationControlImpl;
@@ -52,7 +49,6 @@ import android.view.InsetsFrameProvider;
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
-import android.view.InsetsState.InternalInsetsType;
import android.view.InternalInsetsAnimationController;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
@@ -81,7 +77,6 @@ class InsetsPolicy {
private final InsetsStateController mStateController;
private final DisplayContent mDisplayContent;
private final DisplayPolicy mPolicy;
- private final IntArray mShowingTransientTypes = new IntArray();
/** For resetting visibilities of insets sources. */
private final InsetsControlTarget mDummyControlTarget = new InsetsControlTarget() {
@@ -95,7 +90,7 @@ class InsetsPolicy {
return;
}
for (InsetsSourceControl control : controls) {
- if (mShowingTransientTypes.indexOf(control.getId()) != -1) {
+ if (isTransient(control.getType())) {
// The visibilities of transient bars will be handled with animations.
continue;
}
@@ -117,13 +112,16 @@ class InsetsPolicy {
};
private WindowState mFocusedWin;
- private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
- private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
+ private final BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
+ private final BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
+ private @InsetsType int mShowingTransientTypes;
private boolean mAnimatingShown;
+
/**
* Let remote insets controller control system bars regardless of other settings.
*/
private boolean mRemoteInsetsControllerControlsSystemBars;
+
private final boolean mHideNavBarForKeyboard;
private final float[] mTmpFloat9 = new float[9];
@@ -178,37 +176,46 @@ class InsetsPolicy {
mNavBar.updateVisibility(navControlTarget, Type.navigationBars());
}
- boolean isHidden(@InternalInsetsType int type) {
- final WindowContainerInsetsSourceProvider provider = mStateController
- .peekSourceProvider(type);
- return provider != null && provider.hasWindowContainer()
- && !provider.getSource().isVisible();
+ boolean hasHiddenSources(@InsetsType int types) {
+ final InsetsState state = mStateController.getRawInsetsState();
+ for (int i = state.sourceSize() - 1; i >= 0; i--) {
+ final InsetsSource source = state.sourceAt(i);
+ if ((source.getType() & types) == 0) {
+ continue;
+ }
+ if (!source.getFrame().isEmpty() && !source.isVisible()) {
+ return true;
+ }
+ }
+ return false;
}
- void showTransient(@InternalInsetsType int[] types, boolean isGestureOnSystemBar) {
- boolean changed = false;
- for (int i = types.length - 1; i >= 0; i--) {
- final @InternalInsetsType int type = types[i];
- if (!isHidden(type)) {
+ void showTransient(@InsetsType int types, boolean isGestureOnSystemBar) {
+ @InsetsType int showingTransientTypes = mShowingTransientTypes;
+ final InsetsState rawState = mStateController.getRawInsetsState();
+ for (int i = rawState.sourceSize() - 1; i >= 0; i--) {
+ final InsetsSource source = rawState.sourceAt(i);
+ if (source.isVisible()) {
continue;
}
- if (mShowingTransientTypes.indexOf(type) != -1) {
+ final @InsetsType int type = source.getType();
+ if ((source.getType() & types) == 0) {
continue;
}
- mShowingTransientTypes.add(type);
- changed = true;
+ showingTransientTypes |= type;
}
- if (changed) {
+ if (mShowingTransientTypes != showingTransientTypes) {
+ mShowingTransientTypes = showingTransientTypes;
StatusBarManagerInternal statusBarManagerInternal =
mPolicy.getStatusBarManagerInternal();
if (statusBarManagerInternal != null) {
statusBarManagerInternal.showTransient(mDisplayContent.getDisplayId(),
- mShowingTransientTypes.toArray(), isGestureOnSystemBar);
+ showingTransientTypes, isGestureOnSystemBar);
}
updateBarControlTarget(mFocusedWin);
dispatchTransientSystemBarsVisibilityChanged(
mFocusedWin,
- isTransient(ITYPE_STATUS_BAR) || isTransient(ITYPE_NAVIGATION_BAR),
+ (showingTransientTypes & (Type.statusBars() | Type.navigationBars())) != 0,
isGestureOnSystemBar);
// The leashes can be created while updating bar control target. The surface transaction
@@ -224,7 +231,7 @@ class InsetsPolicy {
}
void hideTransient() {
- if (mShowingTransientTypes.size() == 0) {
+ if (mShowingTransientTypes == 0) {
return;
}
@@ -235,20 +242,25 @@ class InsetsPolicy {
startAnimation(false /* show */, () -> {
synchronized (mDisplayContent.mWmService.mGlobalLock) {
- for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
+ final ArrayMap<Integer, WindowContainerInsetsSourceProvider> providers =
+ mStateController.getSourceProviders();
+ for (int i = providers.size() - 1; i >= 0; i--) {
+ final WindowContainerInsetsSourceProvider provider = providers.valueAt(i);
+ if (!isTransient(provider.getSource().getType())) {
+ continue;
+ }
// We are about to clear mShowingTransientTypes, we don't want the transient bar
// can cause insets on the client. Restore the client visibility.
- final @InternalInsetsType int type = mShowingTransientTypes.get(i);
- mStateController.getSourceProvider(type).setClientVisible(false);
+ provider.setClientVisible(false);
}
- mShowingTransientTypes.clear();
+ mShowingTransientTypes = 0;
updateBarControlTarget(mFocusedWin);
}
});
}
- boolean isTransient(@InternalInsetsType int type) {
- return mShowingTransientTypes.indexOf(type) != -1;
+ boolean isTransient(@InsetsType int type) {
+ return (mShowingTransientTypes & type) != 0;
}
/**
@@ -280,9 +292,9 @@ class InsetsPolicy {
? token.getFixedRotationTransformInsetsState()
: mStateController.getRawInsetsState();
outInsetsState.set(srcState, true /* copySources */);
- for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
- final InsetsSource source = outInsetsState.peekSource(mShowingTransientTypes.get(i));
- if (source != null) {
+ for (int i = outInsetsState.sourceSize() - 1; i >= 0; i--) {
+ final InsetsSource source = outInsetsState.sourceAt(i);
+ if (isTransient(source.getType())) {
source.setVisible(false);
}
}
@@ -365,18 +377,17 @@ class InsetsPolicy {
private InsetsState adjustVisibilityForTransientTypes(InsetsState originalState) {
InsetsState state = originalState;
- for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
- final @InternalInsetsType int type = mShowingTransientTypes.get(i);
- final InsetsSource originalSource = state.peekSource(type);
- if (originalSource != null && originalSource.isVisible()) {
+ for (int i = state.sourceSize() - 1; i >= 0; i--) {
+ final InsetsSource source = state.sourceAt(i);
+ if (isTransient(source.getType()) && source.isVisible()) {
if (state == originalState) {
// The source will be modified, create a non-deep copy to store the new one.
state = new InsetsState(originalState);
}
// Replace the source with a copy in invisible state.
- final InsetsSource source = new InsetsSource(originalSource);
- source.setVisible(false);
- state.addSource(source);
+ final InsetsSource outSource = new InsetsSource(source);
+ outSource.setVisible(false);
+ state.addSource(outSource);
}
}
return state;
@@ -385,18 +396,23 @@ class InsetsPolicy {
private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState,
boolean copyState) {
if (w.mIsImWindow) {
+ InsetsState state = originalState;
// If navigation bar is not hidden by IME, IME should always receive visible
// navigation bar insets.
final boolean navVisible = !mHideNavBarForKeyboard;
- final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
- if (originalNavSource != null && originalNavSource.isVisible() != navVisible) {
- final InsetsState state = copyState ? new InsetsState(originalState)
- : originalState;
- final InsetsSource navSource = new InsetsSource(originalNavSource);
+ for (int i = originalState.sourceSize() - 1; i >= 0; i--) {
+ final InsetsSource source = originalState.sourceAt(i);
+ if (source.getType() != Type.navigationBars() || source.isVisible() == navVisible) {
+ continue;
+ }
+ if (state == originalState && copyState) {
+ state = new InsetsState(originalState);
+ }
+ final InsetsSource navSource = new InsetsSource(source);
navSource.setVisible(navVisible);
state.addSource(navSource);
- return state;
}
+ return state;
} else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
// During switching tasks with gestural navigation, before the next IME input target
// starts the input, we should adjust and freeze the last IME visibility of the window
@@ -447,23 +463,22 @@ class InsetsPolicy {
* @param caller who changed the insets state.
*/
private void checkAbortTransient(InsetsControlTarget caller) {
- if (mShowingTransientTypes.size() != 0) {
- final IntArray abortTypes = new IntArray();
- final boolean imeRequestedVisible = caller.isRequestedVisible(Type.ime());
- for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) {
- final @InternalInsetsType int type = mShowingTransientTypes.get(i);
- if ((mStateController.isFakeTarget(type, caller)
- && caller.isRequestedVisible(InsetsState.toPublicType(type)))
- || (type == ITYPE_NAVIGATION_BAR && imeRequestedVisible)) {
- mShowingTransientTypes.remove(i);
- abortTypes.add(type);
- }
- }
- StatusBarManagerInternal statusBarManagerInternal =
- mPolicy.getStatusBarManagerInternal();
- if (abortTypes.size() > 0 && statusBarManagerInternal != null) {
- statusBarManagerInternal.abortTransient(
- mDisplayContent.getDisplayId(), abortTypes.toArray());
+ if (mShowingTransientTypes == 0) {
+ return;
+ }
+ final boolean isImeVisible = mStateController.getImeSourceProvider().isClientVisible();
+ final @InsetsType int fakeControllingTypes =
+ mStateController.getFakeControllingTypes(caller);
+ final @InsetsType int abortTypes =
+ (fakeControllingTypes & caller.getRequestedVisibleTypes())
+ | (isImeVisible ? Type.navigationBars() : 0);
+ mShowingTransientTypes &= ~abortTypes;
+ if (abortTypes != 0) {
+ mDisplayContent.setLayoutNeeded();
+ mDisplayContent.mWmService.requestTraversal();
+ final StatusBarManagerInternal statusBarManager = mPolicy.getStatusBarManagerInternal();
+ if (statusBarManager != null) {
+ statusBarManager.abortTransient(mDisplayContent.getDisplayId(), abortTypes);
}
}
}
@@ -473,12 +488,16 @@ class InsetsPolicy {
* updateBarControlTarget(mFocusedWin) after this invocation.
*/
private void abortTransient() {
- StatusBarManagerInternal statusBarManagerInternal = mPolicy.getStatusBarManagerInternal();
- if (statusBarManagerInternal != null) {
- statusBarManagerInternal.abortTransient(
- mDisplayContent.getDisplayId(), mShowingTransientTypes.toArray());
+ if (mShowingTransientTypes == 0) {
+ return;
+ }
+ final StatusBarManagerInternal statusBarManager = mPolicy.getStatusBarManagerInternal();
+ if (statusBarManager != null) {
+ statusBarManager.abortTransient(mDisplayContent.getDisplayId(), mShowingTransientTypes);
}
- mShowingTransientTypes.clear();
+ mShowingTransientTypes = 0;
+ mDisplayContent.setLayoutNeeded();
+ mDisplayContent.mWmService.requestTraversal();
dispatchTransientSystemBarsVisibilityChanged(
mFocusedWin,
@@ -488,7 +507,7 @@ class InsetsPolicy {
private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin,
boolean fake) {
- if (!fake && isShowingTransientTypes(Type.statusBars())) {
+ if (!fake && isTransient(Type.statusBars())) {
return mDummyControlTarget;
}
final WindowState notificationShade = mPolicy.getNotificationShade();
@@ -541,7 +560,7 @@ class InsetsPolicy {
// configured to be hidden by the IME.
return null;
}
- if (!fake && isShowingTransientTypes(Type.navigationBars())) {
+ if (!fake && isTransient(Type.navigationBars())) {
return mDummyControlTarget;
}
if (focusedWin == mPolicy.getNotificationShade()) {
@@ -577,16 +596,6 @@ class InsetsPolicy {
return focusedWin;
}
- private boolean isShowingTransientTypes(@InsetsType int types) {
- final IntArray showingTransientTypes = mShowingTransientTypes;
- for (int i = showingTransientTypes.size() - 1; i >= 0; i--) {
- if ((InsetsState.toPublicType(showingTransientTypes.get(i)) & types) != 0) {
- return true;
- }
- }
- return false;
- }
-
/**
* Determines whether the remote insets controller should take control of system bars for all
* windows.
@@ -622,21 +631,17 @@ class InsetsPolicy {
@VisibleForTesting
void startAnimation(boolean show, Runnable callback) {
- int typesReady = 0;
- final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
- final IntArray showingTransientTypes = mShowingTransientTypes;
- for (int i = showingTransientTypes.size() - 1; i >= 0; i--) {
- final int sourceId = showingTransientTypes.get(i);
- final WindowContainerInsetsSourceProvider provider =
- mStateController.getSourceProvider(sourceId);
- final InsetsSourceControl control = provider.getControl(mDummyControlTarget);
- if (control == null || control.getLeash() == null) {
- continue;
+ @InsetsType int typesReady = 0;
+ final SparseArray<InsetsSourceControl> controlsReady = new SparseArray<>();
+ final InsetsSourceControl[] controls =
+ mStateController.getControlsForDispatch(mDummyControlTarget);
+ for (InsetsSourceControl control : controls) {
+ if (isTransient(control.getType()) && control.getLeash() != null) {
+ typesReady |= control.getType();
+ controlsReady.put(control.getId(), new InsetsSourceControl(control));
}
- typesReady |= control.getType();
- controls.put(sourceId, new InsetsSourceControl(control));
}
- controlAnimationUnchecked(typesReady, controls, show, callback);
+ controlAnimationUnchecked(typesReady, controlsReady, show, callback);
}
private void controlAnimationUnchecked(int typesReady,
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index f5af2929c2bd..3ff37060ae92 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -192,13 +192,6 @@ abstract class InsetsSourceProvider {
}
/**
- * @return Whether there is a window container which backs this source.
- */
- boolean hasWindowContainer() {
- return mWindowContainer != null;
- }
-
- /**
* The source frame can affect the layout of other windows, so this should be called once the
* window container gets laid out.
*/
@@ -363,9 +356,9 @@ abstract class InsetsSourceProvider {
}
/**
- * @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget)
+ * @see InsetsStateController#onControlTargetChanged
*/
- void updateControlForFakeTarget(@Nullable InsetsControlTarget fakeTarget) {
+ void updateFakeControlTarget(@Nullable InsetsControlTarget fakeTarget) {
if (fakeTarget == mFakeControlTarget) {
return;
}
@@ -570,6 +563,10 @@ abstract class InsetsSourceProvider {
return mControlTarget;
}
+ InsetsControlTarget getFakeControlTarget() {
+ return mFakeControlTarget;
+ }
+
boolean isClientVisible() {
return mClientVisible;
}
@@ -609,15 +606,15 @@ abstract class InsetsSourceProvider {
}
if (mControlTarget != null) {
pw.print(prefix + "mControlTarget=");
- pw.println(mControlTarget.getWindow());
+ pw.println(mControlTarget);
}
if (mPendingControlTarget != null) {
pw.print(prefix + "mPendingControlTarget=");
- pw.println(mPendingControlTarget.getWindow());
+ pw.println(mPendingControlTarget);
}
if (mFakeControlTarget != null) {
pw.print(prefix + "mFakeControlTarget=");
- pw.println(mFakeControlTarget.getWindow());
+ pw.println(mFakeControlTarget);
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index a3f62b2c5693..d377a3347d46 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -18,10 +18,6 @@ package com.android.server.wm;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.InsetsSource.ID_IME;
-import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.mandatorySystemGestures;
@@ -42,6 +38,7 @@ import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowInsets;
+import android.view.WindowInsets.Type.InsetsType;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -62,12 +59,10 @@ class InsetsStateController {
private final ArrayMap<Integer, WindowContainerInsetsSourceProvider> mProviders =
new ArrayMap<>();
- private final ArrayMap<InsetsControlTarget, ArrayList<Integer>> mControlTargetTypeMap =
- new ArrayMap<>();
- private final SparseArray<InsetsControlTarget> mTypeControlTargetMap = new SparseArray<>();
-
- /** @see #onControlFakeTargetChanged */
- private final SparseArray<InsetsControlTarget> mTypeFakeControlTargetMap = new SparseArray<>();
+ private final ArrayMap<InsetsControlTarget, ArrayList<InsetsSourceProvider>>
+ mControlTargetProvidersMap = new ArrayMap<>();
+ private final SparseArray<InsetsControlTarget> mIdControlTargetMap = new SparseArray<>();
+ private final SparseArray<InsetsControlTarget> mIdFakeControlTargetMap = new SparseArray<>();
private final ArraySet<InsetsControlTarget> mPendingControlChanged = new ArraySet<>();
@@ -108,14 +103,14 @@ class InsetsStateController {
}
@Nullable InsetsSourceControl[] getControlsForDispatch(InsetsControlTarget target) {
- ArrayList<Integer> controlled = mControlTargetTypeMap.get(target);
+ final ArrayList<InsetsSourceProvider> controlled = mControlTargetProvidersMap.get(target);
if (controlled == null) {
return null;
}
final int size = controlled.size();
final InsetsSourceControl[] result = new InsetsSourceControl[size];
for (int i = 0; i < size; i++) {
- result[i] = mProviders.get(controlled.get(i)).getControl(target);
+ result[i] = controlled.get(i).getControl(target);
}
return result;
}
@@ -208,8 +203,16 @@ class InsetsStateController {
}
}
- boolean isFakeTarget(@InternalInsetsType int type, InsetsControlTarget target) {
- return mTypeFakeControlTargetMap.get(type) == target;
+ @InsetsType int getFakeControllingTypes(InsetsControlTarget target) {
+ @InsetsType int types = 0;
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ final InsetsSourceProvider provider = mProviders.valueAt(i);
+ final InsetsControlTarget fakeControlTarget = provider.getFakeControlTarget();
+ if (target == fakeControlTarget) {
+ types |= provider.getSource().getType();
+ }
+ }
+ return types;
}
void onImeControlTargetChanged(@Nullable InsetsControlTarget imeTarget) {
@@ -217,7 +220,7 @@ class InsetsStateController {
// Make sure that we always have a control target for the IME, even if the IME target is
// null. Otherwise there is no leash that will hide it and IME becomes "randomly" visible.
InsetsControlTarget target = imeTarget != null ? imeTarget : mEmptyImeControlTarget;
- onControlChanged(ID_IME, target);
+ onControlTargetChanged(getImeSourceProvider(), target, false /* fake */);
ProtoLog.d(WM_DEBUG_IME, "onImeControlTargetChanged %s",
target != null ? target.getWindow() : "null");
notifyPendingInsetsControlChanged();
@@ -235,101 +238,88 @@ class InsetsStateController {
@Nullable InsetsControlTarget fakeStatusControlling,
@Nullable InsetsControlTarget navControlling,
@Nullable InsetsControlTarget fakeNavControlling) {
- onControlChanged(ITYPE_STATUS_BAR, statusControlling);
- onControlChanged(ITYPE_NAVIGATION_BAR, navControlling);
- onControlChanged(ITYPE_CLIMATE_BAR, statusControlling);
- onControlChanged(ITYPE_EXTRA_NAVIGATION_BAR, navControlling);
- onControlFakeTargetChanged(ITYPE_STATUS_BAR, fakeStatusControlling);
- onControlFakeTargetChanged(ITYPE_NAVIGATION_BAR, fakeNavControlling);
- onControlFakeTargetChanged(ITYPE_CLIMATE_BAR, fakeStatusControlling);
- onControlFakeTargetChanged(ITYPE_EXTRA_NAVIGATION_BAR, fakeNavControlling);
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ final InsetsSourceProvider provider = mProviders.valueAt(i);
+ final @InsetsType int type = provider.getSource().getType();
+ if (type == WindowInsets.Type.statusBars()) {
+ onControlTargetChanged(provider, statusControlling, false /* fake */);
+ onControlTargetChanged(provider, fakeStatusControlling, true /* fake */);
+ } else if (type == WindowInsets.Type.navigationBars()) {
+ onControlTargetChanged(provider, navControlling, false /* fake */);
+ onControlTargetChanged(provider, fakeNavControlling, true /* fake */);
+ }
+ }
notifyPendingInsetsControlChanged();
}
void notifyControlRevoked(@NonNull InsetsControlTarget previousControlTarget,
InsetsSourceProvider provider) {
- removeFromControlMaps(previousControlTarget, provider.getSource().getId(),
- false /* fake */);
+ removeFromControlMaps(previousControlTarget, provider, false /* fake */);
}
- private void onControlChanged(@InternalInsetsType int type,
- @Nullable InsetsControlTarget target) {
- final InsetsControlTarget previous = mTypeControlTargetMap.get(type);
- if (target == previous) {
- return;
- }
- final WindowContainerInsetsSourceProvider provider = mProviders.get(type);
- if (provider == null) {
+ private void onControlTargetChanged(InsetsSourceProvider provider,
+ @Nullable InsetsControlTarget target, boolean fake) {
+ final InsetsControlTarget lastTarget = fake
+ ? mIdFakeControlTargetMap.get(provider.getSource().getId())
+ : mIdControlTargetMap.get(provider.getSource().getId());
+ if (target == lastTarget) {
return;
}
if (!provider.isControllable()) {
return;
}
- provider.updateControlForTarget(target, false /* force */);
- target = provider.getControlTarget();
- if (previous != null) {
- removeFromControlMaps(previous, type, false /* fake */);
- mPendingControlChanged.add(previous);
- }
- if (target != null) {
- addToControlMaps(target, type, false /* fake */);
- mPendingControlChanged.add(target);
- }
- }
+ if (fake) {
+ // The fake target updated here will be used to pretend to the app that it's still under
+ // control of the bars while it's not really, but we still need to find out the apps
+ // intentions around showing/hiding. For example, when the transient bars are showing,
+ // and the fake target requests to show system bars, the transient state will be
+ // aborted.
+ provider.updateFakeControlTarget(target);
+ } else {
+ provider.updateControlForTarget(target, false /* force */);
- /**
- * The fake target saved here will be used to pretend to the app that it's still under control
- * of the bars while it's not really, but we still need to find out the apps intentions around
- * showing/hiding. For example, when the transient bars are showing, and the fake target
- * requests to show system bars, the transient state will be aborted.
- */
- void onControlFakeTargetChanged(@InternalInsetsType int type,
- @Nullable InsetsControlTarget fakeTarget) {
- final InsetsControlTarget previous = mTypeFakeControlTargetMap.get(type);
- if (fakeTarget == previous) {
- return;
- }
- final WindowContainerInsetsSourceProvider provider = mProviders.get(type);
- if (provider == null) {
- return;
+ // Get control target again in case the provider didn't accept the one we passed to it.
+ target = provider.getControlTarget();
+ if (target == lastTarget) {
+ return;
+ }
}
- provider.updateControlForFakeTarget(fakeTarget);
- if (previous != null) {
- removeFromControlMaps(previous, type, true /* fake */);
- mPendingControlChanged.add(previous);
+ if (lastTarget != null) {
+ removeFromControlMaps(lastTarget, provider, fake);
+ mPendingControlChanged.add(lastTarget);
}
- if (fakeTarget != null) {
- addToControlMaps(fakeTarget, type, true /* fake */);
- mPendingControlChanged.add(fakeTarget);
+ if (target != null) {
+ addToControlMaps(target, provider, fake);
+ mPendingControlChanged.add(target);
}
}
private void removeFromControlMaps(@NonNull InsetsControlTarget target,
- @InternalInsetsType int type, boolean fake) {
- final ArrayList<Integer> array = mControlTargetTypeMap.get(target);
+ InsetsSourceProvider provider, boolean fake) {
+ final ArrayList<InsetsSourceProvider> array = mControlTargetProvidersMap.get(target);
if (array == null) {
return;
}
- array.remove((Integer) type);
+ array.remove(provider);
if (array.isEmpty()) {
- mControlTargetTypeMap.remove(target);
+ mControlTargetProvidersMap.remove(target);
}
if (fake) {
- mTypeFakeControlTargetMap.remove(type);
+ mIdFakeControlTargetMap.remove(provider.getSource().getId());
} else {
- mTypeControlTargetMap.remove(type);
+ mIdControlTargetMap.remove(provider.getSource().getId());
}
}
private void addToControlMaps(@NonNull InsetsControlTarget target,
- @InternalInsetsType int type, boolean fake) {
- final ArrayList<Integer> array = mControlTargetTypeMap.computeIfAbsent(target,
- key -> new ArrayList<>());
- array.add(type);
+ InsetsSourceProvider provider, boolean fake) {
+ final ArrayList<InsetsSourceProvider> array = mControlTargetProvidersMap.computeIfAbsent(
+ target, key -> new ArrayList<>());
+ array.add(provider);
if (fake) {
- mTypeFakeControlTargetMap.put(type, target);
+ mIdFakeControlTargetMap.put(provider.getSource().getId(), target);
} else {
- mTypeControlTargetMap.put(type, target);
+ mIdControlTargetMap.put(provider.getSource().getId(), target);
}
}
@@ -351,7 +341,7 @@ class InsetsStateController {
for (int i = mPendingControlChanged.size() - 1; i >= 0; i--) {
final InsetsControlTarget controlTarget = mPendingControlChanged.valueAt(i);
controlTarget.notifyInsetsControlChanged();
- if (mControlTargetTypeMap.containsKey(controlTarget)) {
+ if (mControlTargetProvidersMap.containsKey(controlTarget)) {
// We only collect targets who get controls, not lose controls.
newControlTargets.add(controlTarget);
}
@@ -377,10 +367,25 @@ class InsetsStateController {
prefix = prefix + " ";
mState.dump(prefix, pw);
pw.println(prefix + "Control map:");
- for (int i = mTypeControlTargetMap.size() - 1; i >= 0; i--) {
+ for (int i = mControlTargetProvidersMap.size() - 1; i >= 0; i--) {
+ final InsetsControlTarget controlTarget = mControlTargetProvidersMap.keyAt(i);
pw.print(prefix + " ");
- pw.println(InsetsState.typeToString(mTypeControlTargetMap.keyAt(i)) + " -> "
- + mTypeControlTargetMap.valueAt(i));
+ pw.print(controlTarget);
+ pw.println(":");
+ final ArrayList<InsetsSourceProvider> providers = mControlTargetProvidersMap.valueAt(i);
+ for (int j = providers.size() - 1; j >= 0; j--) {
+ final InsetsSourceProvider provider = providers.get(j);
+ if (provider != null) {
+ pw.print(prefix + " ");
+ if (controlTarget == provider.getFakeControlTarget()) {
+ pw.print("(fake) ");
+ }
+ pw.println(provider.getControl(controlTarget));
+ }
+ }
+ }
+ if (mControlTargetProvidersMap.isEmpty()) {
+ pw.print(prefix + " none");
}
pw.println(prefix + "InsetsSourceProviders:");
for (int i = mProviders.size() - 1; i >= 0; i--) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index 99f7905a9f70..e605a317f096 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.content.ComponentName;
+import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.common.OperationContext;
@@ -364,6 +365,16 @@ public class FingerprintAuthenticationClientTest {
showHideOverlay(c -> c.onLockoutPermanent());
}
+ @Test
+ public void testPowerPressForwardsErrorMessage() throws RemoteException {
+ final FingerprintAuthenticationClient client = createClient();
+
+ client.onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR,
+ BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED);
+
+ verify(mClientMonitorCallbackConverter).onError(anyInt(), anyInt(),
+ eq(BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED), eq(0));
+ }
private void showHideOverlay(Consumer<FingerprintAuthenticationClient> block)
throws RemoteException {
final FingerprintAuthenticationClient client = createClient();
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index 26524d7df7c3..a40d3fe3a3d6 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -16,8 +16,6 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
-import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED;
-
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -29,6 +27,7 @@ import static org.mockito.Mockito.same;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.common.OperationContext;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.PointerContext;
@@ -276,11 +275,12 @@ public class FingerprintEnrollClientTest {
@Test
public void testPowerPressForwardsAcquireMessage() throws RemoteException {
final FingerprintEnrollClient client = createClient();
- client.start(mCallback);
- client.onPowerPressed();
+
+ client.onAcquired(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR,
+ BiometricFingerprintConstants.BIOMETRIC_ERROR_POWER_PRESSED);
verify(mClientMonitorCallbackConverter).onAcquired(anyInt(),
- eq(FINGERPRINT_ACQUIRED_POWER_PRESSED), anyInt());
+ eq(BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_POWER_PRESSED), eq(0));
}
private void showHideOverlay(Consumer<FingerprintEnrollClient> block)
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
index dba299566f84..1a126cfa5c2c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java
@@ -280,8 +280,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
assertFalse(mDisplayContent.getInsetsStateController().getRawInsetsState()
.isSourceOrDefaultVisible(ITYPE_NAVIGATION_BAR, navigationBars()));
- policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR},
- true /* isGestureOnSystemBar */);
+ policy.showTransient(navigationBars() | statusBars(), true /* isGestureOnSystemBar */);
waitUntilWindowAnimatorIdle();
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -308,11 +307,11 @@ public class InsetsPolicyTest extends WindowTestsBase {
spyOn(policy);
doNothing().when(policy).startAnimation(anyBoolean(), any());
policy.updateBarControlTarget(mAppWindow);
- policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR},
+ policy.showTransient(navigationBars() | statusBars(),
true /* isGestureOnSystemBar */);
waitUntilWindowAnimatorIdle();
- assertTrue(policy.isTransient(ITYPE_STATUS_BAR));
- assertFalse(policy.isTransient(ITYPE_NAVIGATION_BAR));
+ assertTrue(policy.isTransient(statusBars()));
+ assertFalse(policy.isTransient(navigationBars()));
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow);
@@ -344,7 +343,7 @@ public class InsetsPolicyTest extends WindowTestsBase {
spyOn(policy);
doNothing().when(policy).startAnimation(anyBoolean(), any());
policy.updateBarControlTarget(mAppWindow);
- policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR},
+ policy.showTransient(navigationBars() | statusBars(),
true /* isGestureOnSystemBar */);
waitUntilWindowAnimatorIdle();
InsetsSourceControl[] controls =
@@ -393,13 +392,13 @@ public class InsetsPolicyTest extends WindowTestsBase {
spyOn(policy);
doNothing().when(policy).startAnimation(anyBoolean(), any());
policy.updateBarControlTarget(app);
- policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR},
+ policy.showTransient(navigationBars() | statusBars(),
true /* isGestureOnSystemBar */);
final InsetsSourceControl[] controls =
mDisplayContent.getInsetsStateController().getControlsForDispatch(app);
policy.updateBarControlTarget(app2);
- assertFalse(policy.isTransient(ITYPE_STATUS_BAR));
- assertFalse(policy.isTransient(ITYPE_NAVIGATION_BAR));
+ assertFalse(policy.isTransient(statusBars()));
+ assertFalse(policy.isTransient(navigationBars()));
}
private WindowState addNavigationBar() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 88ecd3fe2cea..5df8421d3aea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -351,10 +351,10 @@ public class InsetsStateControllerTest extends WindowTestsBase {
assertTrue(rotatedState.isSourceOrDefaultVisible(ITYPE_STATUS_BAR, statusBars()));
provider.getSource().setVisible(false);
- mDisplayContent.getInsetsPolicy().showTransient(new int[] { ITYPE_STATUS_BAR },
+ mDisplayContent.getInsetsPolicy().showTransient(statusBars(),
true /* isGestureOnSystemBar */);
- assertTrue(mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR));
+ assertTrue(mDisplayContent.getInsetsPolicy().isTransient(statusBars()));
assertFalse(app.getInsetsState().isSourceOrDefaultVisible(ITYPE_STATUS_BAR, statusBars()));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java
index 1e5ec4c4e48c..7d13de84642e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerInsetsSourceProviderTest.java
@@ -170,10 +170,10 @@ public class WindowContainerInsetsSourceProviderTest extends WindowTestsBase {
final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
statusBar.getFrame().set(0, 0, 500, 100);
mProvider.setWindowContainer(statusBar, null, null);
- mProvider.updateControlForFakeTarget(target);
+ mProvider.updateFakeControlTarget(target);
assertNotNull(mProvider.getControl(target));
assertNull(mProvider.getControl(target).getLeash());
- mProvider.updateControlForFakeTarget(null);
+ mProvider.updateFakeControlTarget(null);
assertNull(mProvider.getControl(target));
}