diff options
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)); } |