Merge "Ignore existing test failures" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 4e34b63..59a7cbc 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -21,6 +21,7 @@
// !!! KEEP THIS LIST ALPHABETICAL !!!
"aconfig_mediacodec_flags_java_lib",
"android.adaptiveauth.flags-aconfig-java",
+ "android.app.appfunctions.flags-aconfig-java",
"android.app.contextualsearch.flags-aconfig-java",
"android.app.flags-aconfig-java",
"android.app.ondeviceintelligence-aconfig-java",
@@ -1383,6 +1384,21 @@
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+// AppFunctions
+aconfig_declarations {
+ name: "android.app.appfunctions.flags-aconfig",
+ exportable: true,
+ package: "android.app.appfunctions.flags",
+ container: "system",
+ srcs: ["core/java/android/app/appfunctions/flags/flags.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.app.appfunctions.flags-aconfig-java",
+ aconfig_declarations: "android.app.appfunctions.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
// Adaptive Auth
aconfig_declarations {
name: "android.adaptiveauth.flags-aconfig",
diff --git a/apct-tests/perftests/multiuser/Android.bp b/apct-tests/perftests/multiuser/Android.bp
index 856dba3..9eea712 100644
--- a/apct-tests/perftests/multiuser/Android.bp
+++ b/apct-tests/perftests/multiuser/Android.bp
@@ -45,3 +45,8 @@
"trace_configs/trace_config_multi_user.textproto",
],
}
+
+prebuilt_etc {
+ name: "trace_config_multi_user.textproto",
+ src: ":multi_user_trace_config",
+}
diff --git a/core/api/current.txt b/core/api/current.txt
index ea039a7..36c91758 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10684,6 +10684,7 @@
field public static final String ACTIVITY_SERVICE = "activity";
field public static final String ALARM_SERVICE = "alarm";
field public static final String APPWIDGET_SERVICE = "appwidget";
+ field @FlaggedApi("android.app.appfunctions.flags.enable_app_function_manager") public static final String APP_FUNCTION_SERVICE = "app_function";
field public static final String APP_OPS_SERVICE = "appops";
field public static final String APP_SEARCH_SERVICE = "app_search";
field public static final String AUDIO_SERVICE = "audio";
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e73f471..114a2c4 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.app.appfunctions.flags.Flags.enableAppFunctionManager;
+
import android.accounts.AccountManager;
import android.accounts.IAccountManager;
import android.adservices.AdServicesFrameworkInitializer;
@@ -28,6 +30,8 @@
import android.app.admin.IDevicePolicyManager;
import android.app.ambientcontext.AmbientContextManager;
import android.app.ambientcontext.IAmbientContextManager;
+import android.app.appfunctions.AppFunctionManager;
+import android.app.appfunctions.IAppFunctionManager;
import android.app.appsearch.AppSearchManagerFrameworkInitializer;
import android.app.blob.BlobStoreManagerFrameworkInitializer;
import android.app.contentsuggestions.ContentSuggestionsManager;
@@ -925,6 +929,21 @@
return new CompanionDeviceManager(service, ctx.getOuterContext());
}});
+ if (enableAppFunctionManager()) {
+ registerService(Context.APP_FUNCTION_SERVICE, AppFunctionManager.class,
+ new CachedServiceFetcher<>() {
+ @Override
+ public AppFunctionManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IAppFunctionManager service;
+ //TODO(b/357551503): If the feature not present avoid look up every time
+ service = IAppFunctionManager.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.APP_FUNCTION_SERVICE));
+ return new AppFunctionManager(service, ctx.getOuterContext());
+ }
+ });
+ }
+
registerService(Context.VIRTUAL_DEVICE_SERVICE, VirtualDeviceManager.class,
new CachedServiceFetcher<VirtualDeviceManager>() {
@Override
diff --git a/core/java/android/app/appfunctions/AppFunctionManager.java b/core/java/android/app/appfunctions/AppFunctionManager.java
new file mode 100644
index 0000000..a01e373
--- /dev/null
+++ b/core/java/android/app/appfunctions/AppFunctionManager.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 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 android.app.appfunctions;
+
+import android.annotation.SystemService;
+import android.content.Context;
+
+/**
+ * Provides app functions related functionalities.
+ *
+ * <p>App function is a specific piece of functionality that an app offers to the system. These
+ * functionalities can be integrated into various system features.
+ *
+ * @hide
+ */
+@SystemService(Context.APP_FUNCTION_SERVICE)
+public final class AppFunctionManager {
+ private final IAppFunctionManager mService;
+ private final Context mContext;
+
+ /**
+ * TODO(b/357551503): add comments when implement this class
+ *
+ * @hide
+ */
+ public AppFunctionManager(IAppFunctionManager mService, Context context) {
+ this.mService = mService;
+ this.mContext = context;
+ }
+}
diff --git a/core/java/android/app/appfunctions/IAppFunctionManager.aidl b/core/java/android/app/appfunctions/IAppFunctionManager.aidl
new file mode 100644
index 0000000..018bc75
--- /dev/null
+++ b/core/java/android/app/appfunctions/IAppFunctionManager.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 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 android.app.appfunctions;
+
+/**
+* Interface between an app and the server implementation service (AppFunctionManagerService).
+* @hide
+*/
+oneway interface IAppFunctionManager {
+}
\ No newline at end of file
diff --git a/core/java/android/app/appfunctions/flags/flags.aconfig b/core/java/android/app/appfunctions/flags/flags.aconfig
new file mode 100644
index 0000000..367effc
--- /dev/null
+++ b/core/java/android/app/appfunctions/flags/flags.aconfig
@@ -0,0 +1,11 @@
+package: "android.app.appfunctions.flags"
+container: "system"
+
+flag {
+ name: "enable_app_function_manager"
+ is_exported: true
+ is_fixed_read_only: true
+ namespace: "machine_learning"
+ description: "This flag the new App Function manager system service."
+ bug: "357551503"
+}
\ No newline at end of file
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9aebfc8..9dccc9a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -16,6 +16,7 @@
package android.content;
+import static android.app.appfunctions.flags.Flags.FLAG_ENABLE_APP_FUNCTION_MANAGER;
import static android.content.flags.Flags.FLAG_ENABLE_BIND_PACKAGE_ISOLATED_PROCESS;
import android.annotation.AttrRes;
@@ -51,6 +52,7 @@
import android.app.IServiceConnection;
import android.app.VrManager;
import android.app.ambientcontext.AmbientContextManager;
+import android.app.appfunctions.AppFunctionManager;
import android.app.people.PeopleManager;
import android.app.time.TimeManager;
import android.companion.virtual.VirtualDeviceManager;
@@ -6310,6 +6312,16 @@
/**
* Use with {@link #getSystemService(String)} to retrieve an
+ * {@link AppFunctionManager} for
+ * executing app functions.
+ *
+ * @see #getSystemService(String)
+ */
+ @FlaggedApi(FLAG_ENABLE_APP_FUNCTION_MANAGER)
+ public static final String APP_FUNCTION_SERVICE = "app_function";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve an
* {@link android.content.integrity.AppIntegrityManager}.
* @hide
*/
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index b0ab11f..1fab3cf 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -171,6 +171,17 @@
"include-filter": "android.content.pm.cts.PackageManagerShellCommandMultiUserTest"
}
]
+ },
+ {
+ "name":"CtsPackageInstallerCUJTestCases",
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ }
+ ]
}
]
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index de39847..ff737a4 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -58,8 +58,6 @@
import static android.view.inputmethod.Flags.ctrlShiftShortcut;
import static android.view.inputmethod.Flags.predictiveBackIme;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
import android.annotation.AnyThread;
import android.annotation.CallSuper;
import android.annotation.DrawableRes;
@@ -500,36 +498,53 @@
public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3;
/**
- * Enum flag to be used for {@link #setBackDisposition(int)}.
+ * The disposition mode that indicates the expected affordance for the back button.
*
* @hide
*/
- @Retention(SOURCE)
- @IntDef(value = {BACK_DISPOSITION_DEFAULT, BACK_DISPOSITION_WILL_NOT_DISMISS,
- BACK_DISPOSITION_WILL_DISMISS, BACK_DISPOSITION_ADJUST_NOTHING},
- prefix = "BACK_DISPOSITION_")
+ @IntDef(prefix = { "BACK_DISPOSITION_" }, value = {
+ BACK_DISPOSITION_DEFAULT,
+ BACK_DISPOSITION_WILL_NOT_DISMISS,
+ BACK_DISPOSITION_WILL_DISMISS,
+ BACK_DISPOSITION_ADJUST_NOTHING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
public @interface BackDispositionMode {}
/**
+ * The IME is active, and ready to accept touch/key events. It may or may not be visible.
+ *
* @hide
- * The IME is active. It may or may not be visible.
*/
- public static final int IME_ACTIVE = 0x1;
+ public static final int IME_ACTIVE = 1 << 0;
/**
- * @hide
* The IME is perceptibly visible to the user.
+ *
+ * @hide
*/
- public static final int IME_VISIBLE = 0x2;
+ public static final int IME_VISIBLE = 1 << 1;
/**
- * @hide
* The IME is visible, but not yet perceptible to the user (e.g. fading in)
* by {@link android.view.WindowInsetsController}.
*
* @see InputMethodManager#reportPerceptible
+ * @hide
*/
- public static final int IME_VISIBLE_IMPERCEPTIBLE = 0x4;
+ public static final int IME_VISIBLE_IMPERCEPTIBLE = 1 << 2;
+
+ /**
+ * The IME window visibility state.
+ *
+ * @hide
+ */
+ @IntDef(flag = true, prefix = { "IME_" }, value = {
+ IME_ACTIVE,
+ IME_VISIBLE,
+ IME_VISIBLE_IMPERCEPTIBLE,
+ })
+ public @interface ImeWindowVisibility {}
// Min and max values for back disposition.
private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
@@ -1342,7 +1357,8 @@
mImeSurfaceRemoverRunnable = null;
}
- private void setImeWindowStatus(int visibilityFlags, int backDisposition) {
+ private void setImeWindowStatus(@ImeWindowVisibility int visibilityFlags,
+ @BackDispositionMode int backDisposition) {
mPrivOps.setImeWindowStatusAsync(visibilityFlags, backDisposition);
}
@@ -3301,7 +3317,7 @@
ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_HIDE_WINDOW);
ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper,
null /* icProto */);
- setImeWindowStatus(0, mBackDisposition);
+ setImeWindowStatus(0 /* visibilityFlags */, mBackDisposition);
if (android.view.inputmethod.Flags.refactorInsetsController()) {
// The ImeInsetsSourceProvider need the statsToken when dispatching the control. We
// send the token here, so that another request in the provider can be cancelled.
@@ -4476,6 +4492,7 @@
};
}
+ @ImeWindowVisibility
private int mapToImeWindowStatus() {
return IME_ACTIVE
| (isInputViewShown() ? IME_VISIBLE : 0);
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 09306c7..288be9c 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -28,6 +28,7 @@
import android.os.SystemProperties;
import android.util.AttributeSet;
import android.util.TypedValue;
+import android.view.WindowInsets;
import dalvik.system.CloseGuard;
@@ -881,12 +882,13 @@
}
/**
- * @return if a window animation has outsets applied to it.
+ * @return the edges to which outsets should be applied if run as a windoow animation.
*
* @hide
*/
- public boolean hasExtension() {
- return false;
+ @WindowInsets.Side.InsetsSide
+ public int getExtensionEdges() {
+ return 0x0;
}
/**
diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java
index 5aaa994..bbdc9d0 100644
--- a/core/java/android/view/animation/AnimationSet.java
+++ b/core/java/android/view/animation/AnimationSet.java
@@ -21,6 +21,7 @@
import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
+import android.view.WindowInsets;
import java.util.ArrayList;
import java.util.List;
@@ -540,12 +541,12 @@
/** @hide */
@Override
- public boolean hasExtension() {
+ @WindowInsets.Side.InsetsSide
+ public int getExtensionEdges() {
+ int edge = 0x0;
for (Animation animation : mAnimations) {
- if (animation.hasExtension()) {
- return true;
- }
+ edge |= animation.getExtensionEdges();
}
- return false;
+ return edge;
}
}
diff --git a/core/java/android/view/animation/ExtendAnimation.java b/core/java/android/view/animation/ExtendAnimation.java
index 210eb8a..1aeee07 100644
--- a/core/java/android/view/animation/ExtendAnimation.java
+++ b/core/java/android/view/animation/ExtendAnimation.java
@@ -20,6 +20,7 @@
import android.content.res.TypedArray;
import android.graphics.Insets;
import android.util.AttributeSet;
+import android.view.WindowInsets;
/**
* An animation that controls the outset of an object.
@@ -151,9 +152,12 @@
/** @hide */
@Override
- public boolean hasExtension() {
- return mFromInsets.left < 0 || mFromInsets.top < 0 || mFromInsets.right < 0
- || mFromInsets.bottom < 0;
+ @WindowInsets.Side.InsetsSide
+ public int getExtensionEdges() {
+ return (mFromInsets.left < 0 || mToInsets.left < 0 ? WindowInsets.Side.LEFT : 0)
+ | (mFromInsets.right < 0 || mToInsets.right < 0 ? WindowInsets.Side.RIGHT : 0)
+ | (mFromInsets.top < 0 || mToInsets.top < 0 ? WindowInsets.Side.TOP : 0)
+ | (mFromInsets.bottom < 0 || mToInsets.bottom < 0 ? WindowInsets.Side.BOTTOM : 0);
}
@Override
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index a6ae948..adbc598 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -61,16 +61,6 @@
flag {
namespace: "windowing_sdk"
- name: "fix_pip_restore_to_overlay"
- description: "Restore exit-pip activity back to ActivityEmbedding overlay"
- bug: "297887697"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "windowing_sdk"
name: "activity_embedding_animation_customization_flag"
description: "Whether the animation customization feature for AE is enabled"
bug: "293658614"
@@ -128,3 +118,11 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "windowing_sdk"
+ name: "ae_back_stack_restore"
+ description: "Allow the ActivityEmbedding back stack to be restored after process restarted"
+ bug: "289875940"
+ is_fixed_read_only: true
+}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 921363c..b009c99 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -20,6 +20,8 @@
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
@@ -106,13 +108,10 @@
*
* @param vis visibility flags
* @param backDisposition disposition flags
- * @see android.inputmethodservice.InputMethodService#IME_ACTIVE
- * @see android.inputmethodservice.InputMethodService#IME_VISIBLE
- * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_DEFAULT
- * @see android.inputmethodservice.InputMethodService#BACK_DISPOSITION_ADJUST_NOTHING
*/
@AnyThread
- public void setImeWindowStatusAsync(int vis, int backDisposition) {
+ public void setImeWindowStatusAsync(@ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition) {
final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
if (ops == null) {
return;
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index 69d1cb3..7bfb800 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -210,8 +210,16 @@
*/
public static final int CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE = 116;
+ /**
+ * Track interaction of exiting desktop mode on closing the last window.
+ *
+ * <p>Tracking starts when the last window is closed and finishes when the animation to exit
+ * desktop mode ends.
+ */
+ public static final int CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE = 117;
+
// When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
- @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE;
+ @VisibleForTesting static final int LAST_CUJ = CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE;
/** @hide */
@IntDef({
@@ -319,7 +327,8 @@
CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_OPEN,
CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_CLOSE,
CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH,
- CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE
+ CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE,
+ CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {}
@@ -438,6 +447,7 @@
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_CLOSE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_KEYBOARD_QUICK_SWITCH_CLOSE;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH;
CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE;
+ CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE;
}
private Cuj() {
@@ -666,6 +676,8 @@
return "LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH";
case CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE:
return "DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE";
+ case CUJ_DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE:
+ return "DESKTOP_MODE_EXIT_MODE_ON_LAST_WINDOW_CLOSE";
}
return "UNKNOWN";
}
diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
index 7240aff..3adc6b2 100644
--- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
+++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
@@ -16,6 +16,8 @@
package com.android.internal.statusbar;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArrayMap;
@@ -30,7 +32,9 @@
public final int mDisabledFlags1; // switch[0]
public final int mAppearance; // switch[1]
public final AppearanceRegion[] mAppearanceRegions; // switch[2]
+ @ImeWindowVisibility
public final int mImeWindowVis; // switch[3]
+ @BackDispositionMode
public final int mImeBackDisposition; // switch[4]
public final boolean mShowImeSwitcher; // switch[5]
public final int mDisabledFlags2; // switch[6]
@@ -42,10 +46,11 @@
public final LetterboxDetails[] mLetterboxDetails;
public RegisterStatusBarResult(ArrayMap<String, StatusBarIcon> icons, int disabledFlags1,
- int appearance, AppearanceRegion[] appearanceRegions, int imeWindowVis,
- int imeBackDisposition, boolean showImeSwitcher, int disabledFlags2,
- boolean navbarColorManagedByIme, int behavior, int requestedVisibleTypes,
- String packageName, int transientBarTypes, LetterboxDetails[] letterboxDetails) {
+ int appearance, AppearanceRegion[] appearanceRegions,
+ @ImeWindowVisibility int imeWindowVis, @BackDispositionMode int imeBackDisposition,
+ boolean showImeSwitcher, int disabledFlags2, boolean navbarColorManagedByIme,
+ int behavior, int requestedVisibleTypes, String packageName, int transientBarTypes,
+ LetterboxDetails[] letterboxDetails) {
mIcons = new ArrayMap<>(icons);
mDisabledFlags1 = disabledFlags1;
mAppearance = appearance;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 25e7107..26d180c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -695,12 +695,8 @@
break;
case TYPE_ACTIVITY_REPARENTED_TO_TASK:
final IBinder candidateAssociatedActToken, lastOverlayToken;
- if (Flags.fixPipRestoreToOverlay()) {
- candidateAssociatedActToken = change.getOtherActivityToken();
- lastOverlayToken = change.getTaskFragmentToken();
- } else {
- candidateAssociatedActToken = lastOverlayToken = null;
- }
+ candidateAssociatedActToken = change.getOtherActivityToken();
+ lastOverlayToken = change.getTaskFragmentToken();
onActivityReparentedToTask(
wct,
taskId,
@@ -1023,10 +1019,6 @@
@Nullable
OverlayContainerRestoreParams getOverlayContainerRestoreParams(
@Nullable IBinder associatedActivityToken, @Nullable IBinder overlayToken) {
- if (!Flags.fixPipRestoreToOverlay()) {
- return null;
- }
-
if (associatedActivityToken == null || overlayToken == null) {
return null;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index d0e2c99..ee3e6f3 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -36,7 +36,6 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.window.flags.Flags;
import java.util.ArrayList;
import java.util.Collections;
@@ -257,7 +256,7 @@
mPendingAppearedIntent = pendingAppearedIntent;
// Save the information necessary for restoring the overlay when needed.
- if (Flags.fixPipRestoreToOverlay() && overlayTag != null && pendingAppearedIntent != null
+ if (overlayTag != null && pendingAppearedIntent != null
&& associatedActivity != null && !associatedActivity.isFinishing()) {
final IBinder associatedActivityToken = associatedActivity.getActivityToken();
final OverlayContainerRestoreParams params = new OverlayContainerRestoreParams(mToken,
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
index 475475b..90eeb58 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/OverlayPresentationTest.java
@@ -874,8 +874,6 @@
@Test
public void testOnActivityReparentedToTask_overlayRestoration() {
- mSetFlagRule.enableFlags(Flags.FLAG_FIX_PIP_RESTORE_TO_OVERLAY);
-
// Prepares and mock the data necessary for the test.
final IBinder activityToken = mActivity.getActivityToken();
final Intent intent = new Intent();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
index 8d30db6..5355138 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
@@ -18,6 +18,7 @@
import static android.graphics.Matrix.MTRANS_X;
import static android.graphics.Matrix.MTRANS_Y;
+import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import android.annotation.CallSuper;
import android.graphics.Point;
@@ -146,6 +147,14 @@
/** To be overridden by subclasses to adjust the animation surface change. */
void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
// Update the surface position and alpha.
+ if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader()
+ && mAnimation.getExtensionEdges() != 0x0
+ && !(mChange.hasFlags(FLAG_TRANSLUCENT)
+ && mChange.getActivityComponent() != null)) {
+ // Extend non-translucent activities
+ t.setEdgeExtensionEffect(mLeash, mAnimation.getExtensionEdges());
+ }
+
mTransformation.getMatrix().postTranslate(mContentRelOffset.x, mContentRelOffset.y);
t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
t.setAlpha(mLeash, mTransformation.getAlpha());
@@ -165,7 +174,7 @@
if (!cropRect.intersect(mWholeAnimationBounds)) {
// Hide the surface when it is outside of the animation area.
t.setAlpha(mLeash, 0);
- } else if (mAnimation.hasExtension()) {
+ } else if (mAnimation.getExtensionEdges() != 0) {
// Allow the surface to be shown in its original bounds in case we want to use edge
// extensions.
cropRect.union(mContentBounds);
@@ -180,6 +189,10 @@
@CallSuper
void onAnimationEnd(@NonNull SurfaceControl.Transaction t) {
onAnimationUpdate(t, mAnimation.getDuration());
+ if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader()
+ && mAnimation.getExtensionEdges() != 0x0) {
+ t.setEdgeExtensionEffect(mLeash, /* edge */ 0);
+ }
}
final long getDurationHint() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index 5696a54..d2cef4b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -144,8 +144,10 @@
// ending states.
prepareForJumpCut(info, startTransaction);
} else {
- addEdgeExtensionIfNeeded(startTransaction, finishTransaction,
- postStartTransactionCallbacks, adapters);
+ if (!com.android.graphics.libgui.flags.Flags.edgeExtensionShader()) {
+ addEdgeExtensionIfNeeded(startTransaction, finishTransaction,
+ postStartTransactionCallbacks, adapters);
+ }
addBackgroundColorIfNeeded(info, startTransaction, finishTransaction, adapters);
for (ActivityEmbeddingAnimationAdapter adapter : adapters) {
duration = Math.max(duration, adapter.getDurationHint());
@@ -341,7 +343,7 @@
@NonNull List<ActivityEmbeddingAnimationAdapter> adapters) {
for (ActivityEmbeddingAnimationAdapter adapter : adapters) {
final Animation animation = adapter.mAnimation;
- if (!animation.hasExtension()) {
+ if (animation.getExtensionEdges() == 0) {
continue;
}
if (adapter.mChange.hasFlags(FLAG_TRANSLUCENT)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 7275c64..1242287 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -95,6 +95,7 @@
import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Predicate;
/**
* Controls the window animation run when a user initiates a back gesture.
@@ -1209,7 +1210,7 @@
}
if (info.getType() != WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION
- && !isGestureBackTransition(info)) {
+ && isNotGestureBackTransition(info)) {
return false;
}
@@ -1364,7 +1365,7 @@
// try to handle unexpected transition
mergePendingTransitions(info);
- if (!isGestureBackTransition(info) || shouldCancelAnimation(info)
+ if (isNotGestureBackTransition(info) || shouldCancelAnimation(info)
|| !mCloseTransitionRequested) {
if (mPrepareOpenTransition != null) {
applyFinishOpenTransition();
@@ -1395,8 +1396,8 @@
// Cancel close animation if something happen unexpected, let another handler to handle
private boolean shouldCancelAnimation(@NonNull TransitionInfo info) {
- final boolean noCloseAllowed =
- info.getType() == WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION;
+ final boolean noCloseAllowed = !mCloseTransitionRequested
+ && info.getType() == WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION;
boolean unableToHandle = false;
boolean filterTargets = false;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
@@ -1455,7 +1456,11 @@
if (info.getType() != WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION) {
return false;
}
-
+ // Must have open target, must not have close target.
+ if (hasAnimationInMode(info, TransitionUtil::isClosingMode)
+ || !hasAnimationInMode(info, TransitionUtil::isOpeningMode)) {
+ return false;
+ }
SurfaceControl openingLeash = null;
if (mApps != null) {
for (int i = mApps.length - 1; i >= 0; --i) {
@@ -1482,17 +1487,6 @@
return true;
}
- private boolean isGestureBackTransition(@NonNull TransitionInfo info) {
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change c = info.getChanges().get(i);
- if (c.hasFlags(FLAG_BACK_GESTURE_ANIMATED)
- && (TransitionUtil.isOpeningMode(c.getMode())
- || TransitionUtil.isClosingMode(c.getMode()))) {
- return true;
- }
- }
- return false;
- }
/**
* Check whether this transition is triggered from back gesture commitment.
* Reparent the transition targets to animation leashes, so the animation won't be broken.
@@ -1501,10 +1495,18 @@
@NonNull SurfaceControl.Transaction st,
@NonNull SurfaceControl.Transaction ft,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- if (info.getType() == WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION
- || !mCloseTransitionRequested) {
+ if (!mCloseTransitionRequested) {
return false;
}
+ // must have close target
+ if (!hasAnimationInMode(info, TransitionUtil::isClosingMode)) {
+ return false;
+ }
+ if (mApps == null) {
+ // animation is done
+ applyAndFinish(st, ft, finishCallback);
+ return true;
+ }
SurfaceControl openingLeash = null;
SurfaceControl closingLeash = null;
for (int i = mApps.length - 1; i >= 0; --i) {
@@ -1522,6 +1524,7 @@
final Point offset = c.getEndRelOffset();
st.setPosition(c.getLeash(), offset.x, offset.y);
st.reparent(c.getLeash(), openingLeash);
+ st.setAlpha(c.getLeash(), 1.0f);
} else if (TransitionUtil.isClosingMode(c.getMode())) {
st.reparent(c.getLeash(), closingLeash);
}
@@ -1592,6 +1595,21 @@
}
}
+ private static boolean isNotGestureBackTransition(@NonNull TransitionInfo info) {
+ return !hasAnimationInMode(info, TransitionUtil::isOpenOrCloseMode);
+ }
+
+ private static boolean hasAnimationInMode(@NonNull TransitionInfo info,
+ Predicate<Integer> mode) {
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change c = info.getChanges().get(i);
+ if (c.hasFlags(FLAG_BACK_GESTURE_ANIMATED) && mode.test(c.getMode())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private static ComponentName findComponentName(TransitionInfo.Change change) {
final ComponentName componentName = change.getActivityComponent();
if (componentName != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index efa1031..f002d89 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1601,6 +1601,11 @@
getResources().getColor(android.R.color.system_neutral1_1000)));
mManageMenuScrim.setBackgroundDrawable(new ColorDrawable(
getResources().getColor(android.R.color.system_neutral1_1000)));
+ if (mShowingManage) {
+ // the manage menu location depends on the manage button location which may need a
+ // layout pass, so post this to the looper
+ post(() -> showManageMenu(true));
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
index 73aa7ce..a6ed3b8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
@@ -22,6 +22,7 @@
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.content.Context
import android.os.IBinder
+import android.os.Trace
import android.util.SparseArray
import android.view.SurfaceControl
import android.view.WindowManager
@@ -51,6 +52,8 @@
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
+const val VISIBLE_TASKS_COUNTER_NAME = "DESKTOP_MODE_VISIBLE_TASKS"
+
/**
* A [Transitions.TransitionObserver] that observes transitions and the proposed changes to log
* appropriate desktop mode session log events. This observes transitions related to desktop mode
@@ -292,8 +295,14 @@
val previousTaskInfo = preTransitionVisibleFreeformTasks[taskId]
when {
// new tasks added
- previousTaskInfo == null ->
+ previousTaskInfo == null -> {
desktopModeEventLogger.logTaskAdded(sessionId, currentTaskUpdate)
+ Trace.setCounter(
+ Trace.TRACE_TAG_WINDOW_MANAGER,
+ VISIBLE_TASKS_COUNTER_NAME,
+ postTransitionVisibleFreeformTasks.size().toLong()
+ )
+ }
// old tasks that were resized or repositioned
// TODO(b/347935387): Log changes only once they are stable.
buildTaskUpdateForTask(previousTaskInfo) != currentTaskUpdate ->
@@ -305,6 +314,11 @@
preTransitionVisibleFreeformTasks.forEach { taskId, taskInfo ->
if (!postTransitionVisibleFreeformTasks.containsKey(taskId)) {
desktopModeEventLogger.logTaskRemoved(sessionId, buildTaskUpdateForTask(taskInfo))
+ Trace.setCounter(
+ Trace.TRACE_TAG_WINDOW_MANAGER,
+ VISIBLE_TASKS_COUNTER_NAME,
+ postTransitionVisibleFreeformTasks.size().toLong()
+ )
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 7784784..de6887a2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -502,15 +502,19 @@
backgroundColorForTransition = getTransitionBackgroundColorIfSet(info, change, a,
backgroundColorForTransition);
- if (!isTask && a.hasExtension()) {
- if (!TransitionUtil.isOpeningType(mode)) {
- // Can screenshot now (before startTransaction is applied)
- edgeExtendWindow(change, a, startTransaction, finishTransaction);
+ if (!isTask && a.getExtensionEdges() != 0x0) {
+ if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader()) {
+ finishTransaction.setEdgeExtensionEffect(change.getLeash(), /* edge */ 0);
} else {
- // Need to screenshot after startTransaction is applied otherwise activity
- // may not be visible or ready yet.
- postStartTransactionCallbacks
- .add(t -> edgeExtendWindow(change, a, t, finishTransaction));
+ if (!TransitionUtil.isOpeningType(mode)) {
+ // Can screenshot now (before startTransaction is applied)
+ edgeExtendWindow(change, a, startTransaction, finishTransaction);
+ } else {
+ // Need to screenshot after startTransaction is applied otherwise
+ // activity may not be visible or ready yet.
+ postStartTransactionCallbacks
+ .add(t -> edgeExtendWindow(change, a, t, finishTransaction));
+ }
}
}
@@ -558,7 +562,7 @@
buildSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
mTransactionPool, mMainExecutor, animRelOffset, cornerRadius,
- clipRect);
+ clipRect, change.getActivityComponent() != null);
final TransitionInfo.AnimationOptions options;
if (Flags.moveAnimationOptionsToChange()) {
@@ -823,7 +827,7 @@
@NonNull Animation anim, @NonNull SurfaceControl leash,
@NonNull Runnable finishCallback, @NonNull TransactionPool pool,
@NonNull ShellExecutor mainExecutor, @Nullable Point position, float cornerRadius,
- @Nullable Rect clipRect) {
+ @Nullable Rect clipRect, boolean isActivity) {
final SurfaceControl.Transaction transaction = pool.acquire();
final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
final Transformation transformation = new Transformation();
@@ -835,13 +839,13 @@
final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime());
applyTransformation(currentPlayTime, transaction, leash, anim, transformation, matrix,
- position, cornerRadius, clipRect);
+ position, cornerRadius, clipRect, isActivity);
};
va.addUpdateListener(updateListener);
final Runnable finisher = () -> {
applyTransformation(va.getDuration(), transaction, leash, anim, transformation, matrix,
- position, cornerRadius, clipRect);
+ position, cornerRadius, clipRect, isActivity);
pool.release(transaction);
mainExecutor.execute(() -> {
@@ -931,7 +935,8 @@
a.restrictDuration(MAX_ANIMATION_DURATION);
a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
buildSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
- mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds());
+ mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds(),
+ change.getActivityComponent() != null);
}
private void attachThumbnailAnimation(@NonNull ArrayList<Animator> animations,
@@ -955,7 +960,8 @@
a.restrictDuration(MAX_ANIMATION_DURATION);
a.scaleCurrentDuration(mTransitionAnimationScaleSetting);
buildSurfaceAnimation(animations, a, wt.getSurface(), finisher, mTransactionPool,
- mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds());
+ mMainExecutor, change.getEndRelOffset(), cornerRadius, change.getEndAbsBounds(),
+ change.getActivityComponent() != null);
}
private static int getWallpaperTransitType(TransitionInfo info) {
@@ -1005,9 +1011,14 @@
private static void applyTransformation(long time, SurfaceControl.Transaction t,
SurfaceControl leash, Animation anim, Transformation tmpTransformation, float[] matrix,
- Point position, float cornerRadius, @Nullable Rect immutableClipRect) {
+ Point position, float cornerRadius, @Nullable Rect immutableClipRect,
+ boolean isActivity) {
tmpTransformation.clear();
anim.getTransformation(time, tmpTransformation);
+ if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader()
+ && anim.getExtensionEdges() != 0x0 && isActivity) {
+ t.setEdgeExtensionEffect(leash, anim.getExtensionEdges());
+ }
if (position != null) {
tmpTransformation.getMatrix().postTranslate(position.x, position.y);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
index e196254..1958825 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ScreenRotationAnimation.java
@@ -325,21 +325,21 @@
@NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
buildSurfaceAnimation(animations, mRotateEnterAnimation, mSurfaceControl, finishCallback,
mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
- null /* clipRect */);
+ null /* clipRect */, false /* isActivity */);
}
private void startScreenshotRotationAnimation(@NonNull ArrayList<Animator> animations,
@NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
buildSurfaceAnimation(animations, mRotateExitAnimation, mAnimLeash, finishCallback,
mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
- null /* clipRect */);
+ null /* clipRect */, false /* isActivity */);
}
private void buildScreenshotAlphaAnimation(@NonNull ArrayList<Animator> animations,
@NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
buildSurfaceAnimation(animations, mRotateAlphaAnimation, mAnimLeash, finishCallback,
mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
- null /* clipRect */);
+ null /* clipRect */, false /* isActivity */);
}
private void startColorAnimation(float animationScale, @NonNull ShellExecutor animExecutor) {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
index a5e0550..3ffc9d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
@@ -21,6 +21,7 @@
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
import android.tools.traces.component.ComponentNameMatcher
+import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.ClosePipTransition
import org.junit.FixMethodOrder
import org.junit.Test
@@ -60,7 +61,7 @@
val pipCenterY = pipRegion.centerY()
val displayCenterX = device.displayWidth / 2
val barComponent =
- if (flicker.scenario.isTablet) {
+ if (flicker.scenario.isTablet || Flags.enableTaskbarOnPhones()) {
ComponentNameMatcher.TASK_BAR
} else {
ComponentNameMatcher.NAV_BAR
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt
index dad5db9..a9dba4a 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/MultipleShowImeRequestsInSplitScreen.kt
@@ -17,11 +17,13 @@
package com.android.wm.shell.flicker.splitscreen
import android.platform.test.annotations.Presubmit
+import android.tools.NavBar
import android.tools.Rotation
+import android.tools.ScenarioBuilder
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
-import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.SERVICE_TRACE_CONFIG
import android.tools.traces.component.ComponentNameMatcher
import androidx.test.filters.RequiresDevice
import com.android.wm.shell.flicker.splitscreen.benchmark.MultipleShowImeRequestsInSplitScreenBenchmark
@@ -35,7 +37,7 @@
/**
* Test quick switch between two split pairs.
*
- * To run this test: `atest WMShellFlickerTestsSplitScreenGroup2:MultipleShowImeRequestsInSplitScreen`
+ * To run this test: `atest WMShellFlickerTestsSplitScreenGroupOther:MultipleShowImeRequestsInSplitScreen`
*/
@RequiresDevice
@RunWith(Parameterized::class)
@@ -58,10 +60,22 @@
}
companion object {
+ private fun createFlickerTest(
+ navBarMode: NavBar
+ ) = LegacyFlickerTest(ScenarioBuilder()
+ .withStartRotation(Rotation.ROTATION_0)
+ .withEndRotation(Rotation.ROTATION_0)
+ .withNavBarMode(navBarMode), resultReaderProvider = { scenario ->
+ android.tools.flicker.datastore.CachedResultReader(
+ scenario, SERVICE_TRACE_CONFIG
+ )
+ })
+
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams() = LegacyFlickerTestFactory.nonRotationTests(
- supportedRotations = listOf(Rotation.ROTATION_0)
+ fun getParams() = listOf(
+ createFlickerTest(NavBar.MODE_GESTURAL),
+ createFlickerTest(NavBar.MODE_3BUTTON)
)
}
-}
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt
index 4465a16..acaf021 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt
@@ -28,12 +28,16 @@
import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.taskBarLayerIsVisibleAtStartAndEnd
import com.android.server.wm.flicker.taskBarWindowIsAlwaysVisible
+import com.android.wm.shell.Flags
import org.junit.Assume
import org.junit.Test
interface ICommonAssertions {
val flicker: LegacyFlickerTest
+ val usesTaskbar: Boolean
+ get() = flicker.scenario.isTablet || Flags.enableTaskbarOnPhones()
+
/** Checks that all parts of the screen are covered during the transition */
@Presubmit @Test fun entireScreenCovered() = flicker.entireScreenCovered()
@@ -43,7 +47,7 @@
@Presubmit
@Test
fun navBarLayerIsVisibleAtStartAndEnd() {
- Assume.assumeFalse(flicker.scenario.isTablet)
+ Assume.assumeFalse(usesTaskbar)
flicker.navBarLayerIsVisibleAtStartAndEnd()
}
@@ -54,7 +58,7 @@
@Presubmit
@Test
fun navBarLayerPositionAtStartAndEnd() {
- Assume.assumeFalse(flicker.scenario.isTablet)
+ Assume.assumeFalse(usesTaskbar)
flicker.navBarLayerPositionAtStartAndEnd()
}
@@ -66,7 +70,7 @@
@Presubmit
@Test
fun navBarWindowIsAlwaysVisible() {
- Assume.assumeFalse(flicker.scenario.isTablet)
+ Assume.assumeFalse(usesTaskbar)
flicker.navBarWindowIsAlwaysVisible()
}
@@ -76,7 +80,7 @@
@Presubmit
@Test
fun taskBarLayerIsVisibleAtStartAndEnd() {
- Assume.assumeTrue(flicker.scenario.isTablet)
+ Assume.assumeTrue(usesTaskbar)
flicker.taskBarLayerIsVisibleAtStartAndEnd()
}
@@ -88,7 +92,7 @@
@Presubmit
@Test
fun taskBarWindowIsAlwaysVisible() {
- Assume.assumeTrue(flicker.scenario.isTablet)
+ Assume.assumeTrue(usesTaskbar)
flicker.taskBarWindowIsAlwaysVisible()
}
diff --git a/packages/PackageInstaller/TEST_MAPPING b/packages/PackageInstaller/TEST_MAPPING
index b3fb1e7..ff83610 100644
--- a/packages/PackageInstaller/TEST_MAPPING
+++ b/packages/PackageInstaller/TEST_MAPPING
@@ -28,6 +28,17 @@
},
{
"name": "CtsIntentSignatureTestCases"
+ },
+ {
+ "name": "CtsPackageInstallerCUJTestCases",
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ }
+ ]
}
]
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
index c88c4c9..0e71116 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
@@ -25,6 +25,7 @@
import android.provider.Settings
import androidx.concurrent.futures.DirectExecutor
import com.android.internal.util.ConcurrentUtils
+import com.android.settingslib.volume.shared.AudioLogger
import com.android.settingslib.volume.shared.AudioManagerEventsReceiver
import com.android.settingslib.volume.shared.model.AudioManagerEvent
import com.android.settingslib.volume.shared.model.AudioStream
@@ -99,7 +100,7 @@
private val contentResolver: ContentResolver,
private val backgroundCoroutineContext: CoroutineContext,
private val coroutineScope: CoroutineScope,
- private val logger: Logger,
+ private val logger: AudioLogger,
) : AudioRepository {
private val streamSettingNames: Map<AudioStream, String> =
@@ -117,10 +118,10 @@
override val mode: StateFlow<Int> =
callbackFlow {
- val listener = AudioManager.OnModeChangedListener { newMode -> trySend(newMode) }
- audioManager.addOnModeChangedListener(ConcurrentUtils.DIRECT_EXECUTOR, listener)
- awaitClose { audioManager.removeOnModeChangedListener(listener) }
- }
+ val listener = AudioManager.OnModeChangedListener { newMode -> trySend(newMode) }
+ audioManager.addOnModeChangedListener(ConcurrentUtils.DIRECT_EXECUTOR, listener)
+ awaitClose { audioManager.removeOnModeChangedListener(listener) }
+ }
.onStart { emit(audioManager.mode) }
.flowOn(backgroundCoroutineContext)
.stateIn(coroutineScope, SharingStarted.WhileSubscribed(), audioManager.mode)
@@ -140,14 +141,14 @@
override val communicationDevice: StateFlow<AudioDeviceInfo?>
get() =
callbackFlow {
- val listener = OnCommunicationDeviceChangedListener { trySend(Unit) }
- audioManager.addOnCommunicationDeviceChangedListener(
- ConcurrentUtils.DIRECT_EXECUTOR,
- listener,
- )
+ val listener = OnCommunicationDeviceChangedListener { trySend(Unit) }
+ audioManager.addOnCommunicationDeviceChangedListener(
+ ConcurrentUtils.DIRECT_EXECUTOR,
+ listener,
+ )
- awaitClose { audioManager.removeOnCommunicationDeviceChangedListener(listener) }
- }
+ awaitClose { audioManager.removeOnCommunicationDeviceChangedListener(listener) }
+ }
.filterNotNull()
.map { audioManager.communicationDevice }
.onStart { emit(audioManager.communicationDevice) }
@@ -160,15 +161,15 @@
override fun getAudioStream(audioStream: AudioStream): Flow<AudioStreamModel> {
return merge(
- audioManagerEventsReceiver.events.filter {
- if (it is StreamAudioManagerEvent) {
- it.audioStream == audioStream
- } else {
- true
- }
- },
- volumeSettingChanges(audioStream),
- )
+ audioManagerEventsReceiver.events.filter {
+ if (it is StreamAudioManagerEvent) {
+ it.audioStream == audioStream
+ } else {
+ true
+ }
+ },
+ volumeSettingChanges(audioStream),
+ )
.conflate()
.map { getCurrentAudioStream(audioStream) }
.onStart { emit(getCurrentAudioStream(audioStream)) }
@@ -251,11 +252,4 @@
awaitClose { contentResolver.unregisterContentObserver(observer) }
}
}
-
- interface Logger {
-
- fun onSetVolumeRequested(audioStream: AudioStream, volume: Int)
-
- fun onVolumeUpdateReceived(audioStream: AudioStream, model: AudioStreamModel)
- }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
index 7a66335..ebba7f1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioSharingRepository.kt
@@ -34,6 +34,7 @@
import com.android.settingslib.bluetooth.onSourceConnectedOrRemoved
import com.android.settingslib.volume.data.repository.AudioSharingRepository.Companion.AUDIO_SHARING_VOLUME_MAX
import com.android.settingslib.volume.data.repository.AudioSharingRepository.Companion.AUDIO_SHARING_VOLUME_MIN
+import com.android.settingslib.volume.shared.AudioSharingLogger
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -50,6 +51,7 @@
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.runningFold
import kotlinx.coroutines.flow.stateIn
@@ -90,6 +92,7 @@
private val btManager: LocalBluetoothManager,
private val coroutineScope: CoroutineScope,
private val backgroundCoroutineContext: CoroutineContext,
+ private val logger: AudioSharingLogger
) : AudioSharingRepository {
private val isAudioSharingProfilesReady: StateFlow<Boolean> =
btManager.profileManager.onServiceStateChanged
@@ -104,6 +107,7 @@
btManager.profileManager.leAudioBroadcastProfile.onBroadcastStartedOrStopped
.map { isBroadcasting() }
.onStart { emit(isBroadcasting()) }
+ .onEach { logger.onAudioSharingStateChanged(it) }
.flowOn(backgroundCoroutineContext)
} else {
flowOf(false)
@@ -156,6 +160,7 @@
.map { getSecondaryGroupId() },
primaryGroupId.map { getSecondaryGroupId() })
.onStart { emit(getSecondaryGroupId()) }
+ .onEach { logger.onSecondaryGroupIdChanged(it) }
.flowOn(backgroundCoroutineContext)
.stateIn(
coroutineScope,
@@ -202,6 +207,7 @@
acc
}
}
+ .onEach { logger.onVolumeMapChanged(it) }
.flowOn(backgroundCoroutineContext)
} else {
emptyFlow()
@@ -220,6 +226,7 @@
BluetoothUtils.getSecondaryDeviceForBroadcast(contentResolver, btManager)
if (cachedDevice != null) {
it.setDeviceVolume(cachedDevice.device, volume, /* isGroupOp= */ true)
+ logger.onSetDeviceVolumeRequested(volume)
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioLogger.kt b/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioLogger.kt
new file mode 100644
index 0000000..84f7fcb
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioLogger.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.volume.shared
+
+import com.android.settingslib.volume.shared.model.AudioStream
+import com.android.settingslib.volume.shared.model.AudioStreamModel
+
+/** A log interface for audio streams volume events. */
+interface AudioLogger {
+ fun onSetVolumeRequested(audioStream: AudioStream, volume: Int)
+
+ fun onVolumeUpdateReceived(audioStream: AudioStream, model: AudioStreamModel)
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioSharingLogger.kt b/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioSharingLogger.kt
new file mode 100644
index 0000000..18a4c6d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/shared/AudioSharingLogger.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 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.volume.shared
+
+/** A log interface for audio sharing volume events. */
+interface AudioSharingLogger {
+
+ fun onAudioSharingStateChanged(state: Boolean)
+
+ fun onSecondaryGroupIdChanged(groupId: Int)
+
+ fun onVolumeMapChanged(map: Map<Int, Int>)
+
+ fun onSetDeviceVolumeRequested(volume: Int)
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt
index 078f0c8..8c5a085 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/AudioSharingRepositoryTest.kt
@@ -48,6 +48,7 @@
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
+import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -101,7 +102,7 @@
@Captor
private lateinit var assistantCallbackCaptor:
- ArgumentCaptor<BluetoothLeBroadcastAssistant.Callback>
+ ArgumentCaptor<BluetoothLeBroadcastAssistant.Callback>
@Captor private lateinit var btCallbackCaptor: ArgumentCaptor<BluetoothCallback>
@@ -110,6 +111,7 @@
@Captor
private lateinit var volumeCallbackCaptor: ArgumentCaptor<BluetoothVolumeControl.Callback>
+ private val logger = FakeAudioSharingRepositoryLogger()
private val testScope = TestScope()
private val context: Context = ApplicationProvider.getApplicationContext()
@Spy private val contentResolver: ContentResolver = context.contentResolver
@@ -135,16 +137,23 @@
Settings.Secure.putInt(
contentResolver,
BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
- TEST_GROUP_ID_INVALID)
+ TEST_GROUP_ID_INVALID
+ )
underTest =
AudioSharingRepositoryImpl(
contentResolver,
btManager,
testScope.backgroundScope,
testScope.testScheduler,
+ logger
)
}
+ @After
+ fun tearDown() {
+ logger.reset()
+ }
+
@Test
fun audioSharingStateChange_profileReady_emitValues() {
testScope.runTest {
@@ -160,6 +169,13 @@
runCurrent()
Truth.assertThat(states).containsExactly(false, true, false, true)
+ Truth.assertThat(logger.logs)
+ .containsAtLeastElementsIn(
+ listOf(
+ "onAudioSharingStateChanged state=true",
+ "onAudioSharingStateChanged state=false",
+ )
+ ).inOrder()
}
}
@@ -187,7 +203,8 @@
Truth.assertThat(groupIds)
.containsExactly(
TEST_GROUP_ID_INVALID,
- TEST_GROUP_ID2)
+ TEST_GROUP_ID2
+ )
}
}
@@ -219,13 +236,16 @@
triggerSourceAdded()
runCurrent()
triggerProfileConnectionChange(
- BluetoothAdapter.STATE_CONNECTING, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
+ BluetoothAdapter.STATE_CONNECTING, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
+ )
runCurrent()
triggerProfileConnectionChange(
- BluetoothAdapter.STATE_DISCONNECTED, BluetoothProfile.LE_AUDIO)
+ BluetoothAdapter.STATE_DISCONNECTED, BluetoothProfile.LE_AUDIO
+ )
runCurrent()
triggerProfileConnectionChange(
- BluetoothAdapter.STATE_DISCONNECTED, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT)
+ BluetoothAdapter.STATE_DISCONNECTED, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
+ )
runCurrent()
Truth.assertThat(groupIds)
@@ -235,7 +255,16 @@
TEST_GROUP_ID1,
TEST_GROUP_ID_INVALID,
TEST_GROUP_ID2,
- TEST_GROUP_ID_INVALID)
+ TEST_GROUP_ID_INVALID
+ )
+ Truth.assertThat(logger.logs)
+ .containsAtLeastElementsIn(
+ listOf(
+ "onSecondaryGroupIdChanged groupId=$TEST_GROUP_ID_INVALID",
+ "onSecondaryGroupIdChanged groupId=$TEST_GROUP_ID2",
+ "onSecondaryGroupIdChanged groupId=$TEST_GROUP_ID1",
+ )
+ ).inOrder()
}
}
@@ -257,11 +286,22 @@
verify(volumeControl).unregisterCallback(any())
runCurrent()
+ val expectedMap1 = mapOf(TEST_GROUP_ID1 to TEST_VOLUME1)
+ val expectedMap2 = mapOf(TEST_GROUP_ID1 to TEST_VOLUME2)
Truth.assertThat(volumeMaps)
.containsExactly(
emptyMap<Int, Int>(),
- mapOf(TEST_GROUP_ID1 to TEST_VOLUME1),
- mapOf(TEST_GROUP_ID1 to TEST_VOLUME2))
+ expectedMap1,
+ expectedMap2
+ )
+ Truth.assertThat(logger.logs)
+ .containsAtLeastElementsIn(
+ listOf(
+ "onVolumeMapChanged map={}",
+ "onVolumeMapChanged map=$expectedMap1",
+ "onVolumeMapChanged map=$expectedMap2",
+ )
+ ).inOrder()
}
}
@@ -281,12 +321,19 @@
Settings.Secure.putInt(
contentResolver,
BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
- TEST_GROUP_ID2)
+ TEST_GROUP_ID2
+ )
`when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2))
underTest.setSecondaryVolume(TEST_VOLUME1)
runCurrent()
verify(volumeControl).setDeviceVolume(device1, TEST_VOLUME1, true)
+ Truth.assertThat(logger.logs)
+ .isEqualTo(
+ listOf(
+ "onSetVolumeRequested volume=$TEST_VOLUME1",
+ )
+ )
}
}
@@ -313,7 +360,8 @@
Settings.Secure.putInt(
contentResolver,
BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
- TEST_GROUP_ID1)
+ TEST_GROUP_ID1
+ )
`when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2))
assistantCallbackCaptor.value.sourceAdded(device1, receiveState)
}
@@ -324,7 +372,8 @@
Settings.Secure.putInt(
contentResolver,
BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
- TEST_GROUP_ID1)
+ TEST_GROUP_ID1
+ )
assistantCallbackCaptor.value.sourceRemoved(device2)
}
@@ -334,7 +383,8 @@
Settings.Secure.putInt(
contentResolver,
BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
- TEST_GROUP_ID1)
+ TEST_GROUP_ID1
+ )
btCallbackCaptor.value.onProfileConnectionStateChanged(cachedDevice2, state, profile)
}
@@ -343,12 +393,14 @@
.registerContentObserver(
eq(Settings.Secure.getUriFor(BluetoothUtils.getPrimaryGroupIdUriForBroadcast())),
eq(false),
- contentObserverCaptor.capture())
+ contentObserverCaptor.capture()
+ )
`when`(assistant.allConnectedDevices).thenReturn(listOf(device1, device2))
Settings.Secure.putInt(
contentResolver,
BluetoothUtils.getPrimaryGroupIdUriForBroadcast(),
- TEST_GROUP_ID2)
+ TEST_GROUP_ID2
+ )
contentObserverCaptor.value.primaryChanged()
}
@@ -380,8 +432,9 @@
onBroadcastStopped(TEST_REASON, TEST_BROADCAST_ID)
}
val sourceAdded:
- BluetoothLeBroadcastAssistant.Callback.(
- sink: BluetoothDevice, state: BluetoothLeBroadcastReceiveState) -> Unit =
+ BluetoothLeBroadcastAssistant.Callback.(
+ sink: BluetoothDevice, state: BluetoothLeBroadcastReceiveState
+ ) -> Unit =
{ sink, state ->
onReceiveStateChanged(sink, TEST_SOURCE_ID, state)
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioRepositoryLogger.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioRepositoryLogger.kt
index 389bf53..bd573fb 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioRepositoryLogger.kt
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioRepositoryLogger.kt
@@ -16,10 +16,11 @@
package com.android.settingslib.volume.data.repository
+import com.android.settingslib.volume.shared.AudioLogger
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.settingslib.volume.shared.model.AudioStreamModel
-class FakeAudioRepositoryLogger : AudioRepositoryImpl.Logger {
+class FakeAudioRepositoryLogger : AudioLogger {
private val mutableLogs: MutableList<String> = mutableListOf()
val logs: List<String>
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioSharingRepositoryLogger.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioSharingRepositoryLogger.kt
new file mode 100644
index 0000000..cc4cc8d
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioSharingRepositoryLogger.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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.volume.data.repository
+
+import com.android.settingslib.volume.shared.AudioSharingLogger
+import java.util.concurrent.CopyOnWriteArrayList
+
+class FakeAudioSharingRepositoryLogger : AudioSharingLogger {
+ private val mutableLogs = CopyOnWriteArrayList<String>()
+ val logs: List<String>
+ get() = mutableLogs.toList()
+
+ fun reset() {
+ mutableLogs.clear()
+ }
+
+ override fun onAudioSharingStateChanged(state: Boolean) {
+ mutableLogs.add("onAudioSharingStateChanged state=$state")
+ }
+
+ override fun onSecondaryGroupIdChanged(groupId: Int) {
+ mutableLogs.add("onSecondaryGroupIdChanged groupId=$groupId")
+ }
+
+ override fun onVolumeMapChanged(map: GroupIdToVolumes) {
+ mutableLogs.add("onVolumeMapChanged map=$map")
+ }
+
+ override fun onSetDeviceVolumeRequested(volume: Int) {
+ mutableLogs.add("onSetVolumeRequested volume=$volume")
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 30c4ee5..9ab853f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -690,7 +690,7 @@
Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null,
null, null);
try {
- return extractRelevantValues(cursor, GlobalSettings.SETTINGS_TO_BACKUP);
+ return extractRelevantValues(cursor, getGlobalSettingsToBackup());
} finally {
cursor.close();
}
@@ -1011,7 +1011,7 @@
Settings.System.LEGACY_RESTORE_SETTINGS);
validators = SystemSettingsValidators.VALIDATORS;
} else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
- whitelist = ArrayUtils.concat(String.class, GlobalSettings.SETTINGS_TO_BACKUP,
+ whitelist = ArrayUtils.concat(String.class, getGlobalSettingsToBackup(),
Settings.Global.LEGACY_RESTORE_SETTINGS);
validators = GlobalSettingsValidators.VALIDATORS;
} else {
@@ -1021,6 +1021,17 @@
return new SettingsBackupWhitelist(whitelist, validators);
}
+ private String[] getGlobalSettingsToBackup() {
+ // On watches, we don't want to backup or restore 'bluetooth_on' setting, as setting it to
+ // false during restore would cause watch OOBE to fail due to bluetooth connection loss.
+ if (isWatch()) {
+ return ArrayUtils.removeElement(
+ String.class, GlobalSettings.SETTINGS_TO_BACKUP, Settings.Global.BLUETOOTH_ON);
+ }
+
+ return GlobalSettings.SETTINGS_TO_BACKUP;
+ }
+
private boolean isBlockedByDynamicList(Set<String> dynamicBlockList, Uri areaUri, String key) {
String contentKey = Uri.withAppendedPath(areaUri, key).toString();
return dynamicBlockList.contains(contentKey);
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
index d4ca4a3..3a391505 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
@@ -26,6 +26,7 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.ContextWrapper;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
@@ -221,6 +222,21 @@
}
@Test
+ public void testOnRestore_bluetoothOnRestoredOnNonWearablesOnly() {
+ TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext);
+ mAgentUnderTest.mSettingsHelper = settingsHelper;
+
+ restoreGlobalSettings(generateBackupData(Map.of(Settings.Global.BLUETOOTH_ON, "0")));
+
+ var isWatch = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+ if (isWatch) {
+ assertFalse(settingsHelper.mWrittenValues.containsKey(Settings.Global.BLUETOOTH_ON));
+ } else {
+ assertEquals("0", settingsHelper.mWrittenValues.get(Settings.Global.BLUETOOTH_ON));
+ }
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_CONFIGURABLE_FONT_SCALE_DEFAULT)
public void testFindClosestAllowedFontScale() {
final String[] availableFontScales = new String[]{"0.5", "0.9", "1.0", "1.1", "1.5"};
@@ -266,6 +282,20 @@
return buffer.array();
}
+ private void restoreGlobalSettings(byte[] backupData) {
+ mAgentUnderTest.restoreSettings(
+ backupData,
+ /* pos= */ 0,
+ backupData.length,
+ Settings.Global.CONTENT_URI,
+ null,
+ null,
+ null,
+ R.array.restore_blocked_global_settings,
+ /* dynamicBlockList= */ Collections.emptySet(),
+ /* settingsToPreserve= */ Collections.emptySet());
+ }
+
private byte[] generateUncorruptedHeader() throws IOException {
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
mAgentUnderTest.writeHeader(os);
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 9f3c2bf..1d9f469 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -482,6 +482,15 @@
android:exported="true"
android:theme="@style/Theme.AppCompat.NoActionBar">
<intent-filter>
+ <action android:name="com.android.systemui.action.TOUCHPAD_TUTORIAL"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity"
+ android:exported="true"
+ android:theme="@style/Theme.AppCompat.NoActionBar">
+ <intent-filter>
<action android:name="com.android.systemui.action.TOUCHPAD_KEYBOARD_TUTORIAL"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 1ff9a80..0314992 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1237,6 +1237,16 @@
}
flag {
+ name: "relock_with_power_button_immediately"
+ namespace: "systemui"
+ description: "UDFPS unlock followed by immediate power button push should relock"
+ bug: "343327511"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "lockscreen_preview_renderer_create_on_main_thread"
namespace: "systemui"
description: "Force preview renderer to be created on the main thread"
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
index 26ab10b..85d5d6a 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt
@@ -24,9 +24,11 @@
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.approachLayout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.viewinterop.AndroidView
import com.android.compose.animation.scene.MovableElementKey
import com.android.compose.animation.scene.SceneScope
@@ -51,6 +53,7 @@
mediaHost: MediaHost,
modifier: Modifier = Modifier,
carouselController: MediaCarouselController,
+ offsetProvider: (() -> IntOffset)? = null,
) {
if (!isVisible) {
return
@@ -68,21 +71,38 @@
MovableElement(
key = MediaCarousel.Elements.Content,
- modifier = modifier.height(mediaHeight).fillMaxWidth()
+ modifier = modifier.height(mediaHeight).fillMaxWidth(),
) {
content {
AndroidView(
modifier =
- Modifier.fillMaxSize().layout { measurable, constraints ->
- val placeable = measurable.measure(constraints)
+ Modifier.fillMaxSize()
+ .approachLayout(
+ isMeasurementApproachInProgress = { offsetProvider != null },
+ approachMeasure = { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ layout(placeable.width, placeable.height) {
+ placeable.placeRelative(
+ offsetProvider?.invoke() ?: IntOffset.Zero
+ )
+ }
+ }
+ )
+ .layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
- // Notify controller to size the carousel for the current space
- mediaHost.measurementInput =
- MeasurementInput(placeable.width, placeable.height)
- carouselController.setSceneContainerSize(placeable.width, placeable.height)
+ // Notify controller to size the carousel for the current space
+ mediaHost.measurementInput =
+ MeasurementInput(placeable.width, placeable.height)
+ carouselController.setSceneContainerSize(
+ placeable.width,
+ placeable.height
+ )
- layout(placeable.width, placeable.height) { placeable.placeRelative(0, 0) }
- },
+ layout(placeable.width, placeable.height) {
+ placeable.placeRelative(0, 0)
+ }
+ },
factory = { context ->
FrameLayout(context).apply {
layoutParams =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt
index 3f04f37..70c0db1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaContentPicker.kt
@@ -27,7 +27,6 @@
/** [ElementContentPicker] implementation for the media carousel object. */
object MediaContentPicker : StaticElementContentPicker {
- const val SHADE_FRACTION = 0.66f
override val contents =
setOf(
Scenes.Lockscreen,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
index a9da733..71fa6c9 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt
@@ -25,7 +25,6 @@
import com.android.compose.animation.scene.UserActionDistance
import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.media.controls.ui.composable.MediaCarousel
-import com.android.systemui.media.controls.ui.composable.MediaContentPicker
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.shade.ui.composable.Shade
@@ -54,13 +53,7 @@
fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) }
fractionRange(start = .33f) {
- val qsTranslation =
- ShadeHeader.Dimensions.CollapsedHeight * MediaContentPicker.SHADE_FRACTION
- val qsExpansionDiff =
- ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight
- translate(MediaCarousel.Elements.Content, y = -(qsExpansionDiff + qsTranslation))
fade(MediaCarousel.Elements.Content)
-
fade(ShadeHeader.Elements.Clock)
fade(ShadeHeader.Elements.CollapsedContentStart)
fade(ShadeHeader.Elements.CollapsedContentEnd)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
index 21dfc49..b677dff 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt
@@ -26,7 +26,6 @@
import com.android.compose.animation.scene.UserActionDistance
import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.media.controls.ui.composable.MediaCarousel
-import com.android.systemui.media.controls.ui.composable.MediaContentPicker
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.scene.shared.model.Scenes
@@ -62,12 +61,9 @@
fade(QuickSettings.Elements.FooterActions)
}
- val qsTranslation = ShadeHeader.Dimensions.CollapsedHeight * MediaContentPicker.SHADE_FRACTION
- val qsExpansionDiff =
- ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight
-
- translate(QuickSettings.Elements.QuickQuickSettings, y = -qsTranslation)
- translate(MediaCarousel.Elements.Content, y = -(qsExpansionDiff + qsTranslation))
+ val qsTranslation = -ShadeHeader.Dimensions.CollapsedHeight * 0.66f
+ translate(QuickSettings.Elements.QuickQuickSettings, y = qsTranslation)
+ translate(MediaCarousel.Elements.Content, y = qsTranslation)
translate(Notifications.Elements.NotificationScrim, Edge.Top, false)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeMediaOffsetProvider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeMediaOffsetProvider.kt
new file mode 100644
index 0000000..e0b7909
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeMediaOffsetProvider.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 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.systemui.shade.ui.composable
+
+import androidx.compose.ui.unit.IntOffset
+import com.android.systemui.qs.ui.adapter.QSSceneAdapter
+
+/**
+ * Provider for the extra offset for the Media section in the shade to accommodate for the squishing
+ * qs or qqs tiles.
+ */
+interface ShadeMediaOffsetProvider {
+
+ /** Returns current offset to be applied to the Media Carousel */
+ val offset: IntOffset
+
+ /**
+ * [ShadeMediaOffsetProvider] implementation for Quick Settings.
+ *
+ * [updateLayout] should represent an access to some state to trigger Compose to relayout to
+ * track [QSSceneAdapter] internal state changes during the transition.
+ */
+ class Qs(private val updateLayout: () -> Unit, private val qsSceneAdapter: QSSceneAdapter) :
+ ShadeMediaOffsetProvider {
+
+ override val offset: IntOffset
+ get() =
+ calculateQsOffset(
+ updateLayout,
+ qsSceneAdapter.qsHeight,
+ qsSceneAdapter.squishedQsHeight
+ )
+ }
+
+ /**
+ * [ShadeMediaOffsetProvider] implementation for Quick Quick Settings.
+ *
+ * [updateLayout] should represent an access to some state to trigger Compose to relayout to
+ * track [QSSceneAdapter] internal state changes during the transition.
+ */
+ class Qqs(private val updateLayout: () -> Unit, private val qsSceneAdapter: QSSceneAdapter) :
+ ShadeMediaOffsetProvider {
+
+ override val offset: IntOffset
+ get() =
+ calculateQsOffset(
+ updateLayout,
+ qsSceneAdapter.qqsHeight,
+ qsSceneAdapter.squishedQqsHeight
+ )
+ }
+
+ companion object {
+
+ protected fun calculateQsOffset(
+ updateLayout: () -> Unit,
+ qsHeight: Int,
+ qsSquishedHeight: Int
+ ): IntOffset {
+ updateLayout()
+ val distanceFromBottomToActualBottom = qsHeight - qsSquishedHeight
+ return IntOffset(0, -distanceFromBottomToActualBottom)
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 0e3fcf4..16972bc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -118,7 +118,6 @@
object Shade {
object Elements {
- val MediaCarousel = ElementKey("ShadeMediaCarousel")
val BackgroundScrim =
ElementKey("ShadeBackgroundScrim", contentPicker = LowestZIndexContentPicker)
val SplitShadeStartColumn = ElementKey("SplitShadeStartColumn")
@@ -283,6 +282,13 @@
val navBarHeight = WindowInsets.systemBars.asPaddingValues().calculateBottomPadding()
+ val mediaOffsetProvider = remember {
+ ShadeMediaOffsetProvider.Qqs(
+ { @Suppress("UNUSED_EXPRESSION") tileSquishiness },
+ viewModel.qsSceneAdapter,
+ )
+ }
+
Box(
modifier =
modifier.thenIf(shouldPunchHoleBehindScrim) {
@@ -335,12 +341,12 @@
)
}
- MediaCarousel(
+ ShadeMediaCarousel(
isVisible = isMediaVisible,
mediaHost = mediaHost,
+ mediaOffsetProvider = mediaOffsetProvider,
modifier =
- Modifier.fillMaxWidth()
- .layoutId(QSMediaMeasurePolicy.LayoutId.Media),
+ Modifier.layoutId(QSMediaMeasurePolicy.LayoutId.Media),
carouselController = mediaCarouselController,
)
}
@@ -497,6 +503,13 @@
val brightnessMirrorShowingModifier = Modifier.graphicsLayer { alpha = contentAlpha }
+ val mediaOffsetProvider = remember {
+ ShadeMediaOffsetProvider.Qs(
+ { @Suppress("UNUSED_EXPRESSION") tileSquishiness },
+ viewModel.qsSceneAdapter,
+ )
+ }
+
Box {
Box(
modifier =
@@ -570,11 +583,13 @@
squishiness = { tileSquishiness },
)
}
- MediaCarousel(
+
+ ShadeMediaCarousel(
isVisible = isMediaVisible,
mediaHost = mediaHost,
+ mediaOffsetProvider = mediaOffsetProvider,
modifier =
- Modifier.fillMaxWidth().thenIf(
+ Modifier.thenIf(
MediaContentPicker.shouldElevateMedia(layoutState)
) {
Modifier.zIndex(1f)
@@ -620,3 +635,25 @@
)
}
}
+
+@Composable
+private fun SceneScope.ShadeMediaCarousel(
+ isVisible: Boolean,
+ mediaHost: MediaHost,
+ carouselController: MediaCarouselController,
+ mediaOffsetProvider: ShadeMediaOffsetProvider,
+ modifier: Modifier = Modifier,
+) {
+ MediaCarousel(
+ modifier = modifier.fillMaxWidth(),
+ isVisible = isVisible,
+ mediaHost = mediaHost,
+ carouselController = carouselController,
+ offsetProvider =
+ if (MediaContentPicker.shouldElevateMedia(layoutState)) {
+ null
+ } else {
+ { mediaOffsetProvider.offset }
+ }
+ )
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
index e13ca391..ae5a84b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
@@ -120,7 +120,7 @@
}
@Deprecated(
- "Use animateSceneFloatAsState() instead",
+ "Use animateContentFloatAsState() instead",
replaceWith = ReplaceWith("animateContentFloatAsState(value, key, canOverflow)")
)
@Composable
@@ -171,7 +171,7 @@
}
@Deprecated(
- "Use animateSceneDpAsState() instead",
+ "Use animateContentDpAsState() instead",
replaceWith = ReplaceWith("animateContentDpAsState(value, key, canOverflow)")
)
@Composable
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index a43028a..712fe6b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -459,38 +459,11 @@
animateTo(targetScene = targetScene, targetOffset = targetOffset)
} else {
- // We are doing an overscroll animation between scenes. In this case, we can also start
- // from the idle position.
-
- val startFromIdlePosition = swipeTransition.dragOffset == 0f
-
- if (startFromIdlePosition) {
- // If there is a target scene, we start the overscroll animation.
- val result = swipes.findUserActionResultStrict(velocity)
- if (result == null) {
- // We will not animate
- swipeTransition.snapToScene(fromScene.key)
- return 0f
- }
-
- val newSwipeTransition =
- SwipeTransition(
- layoutState = layoutState,
- coroutineScope = draggableHandler.coroutineScope,
- fromScene = fromScene,
- result = result,
- swipes = swipes,
- layoutImpl = draggableHandler.layoutImpl,
- orientation = draggableHandler.orientation,
- )
- .apply { _currentScene = swipeTransition._currentScene }
-
- updateTransition(newSwipeTransition)
- animateTo(targetScene = fromScene, targetOffset = 0f)
- } else {
- // We were between two scenes: animate to the initial scene.
- animateTo(targetScene = fromScene, targetOffset = 0f)
+ // We are doing an overscroll preview animation between scenes.
+ check(fromScene == swipeTransition._currentScene) {
+ "canChangeScene is false but currentScene != fromScene"
}
+ animateTo(targetScene = fromScene, targetOffset = 0f)
}
// The onStop animation consumes any remaining velocity.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index a30b780..79b3856 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -17,6 +17,8 @@
package com.android.compose.animation.scene
import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.Easing
+import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.SpringSpec
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.ui.geometry.Offset
@@ -140,6 +142,7 @@
fun fractionRange(
start: Float? = null,
end: Float? = null,
+ easing: Easing = LinearEasing,
builder: PropertyTransformationBuilder.() -> Unit,
)
}
@@ -182,6 +185,7 @@
fun timestampRange(
startMillis: Int? = null,
endMillis: Int? = null,
+ easing: Easing = LinearEasing,
builder: PropertyTransformationBuilder.() -> Unit,
)
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index 6515cb8..a63b19a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -18,6 +18,7 @@
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.DurationBasedAnimationSpec
+import androidx.compose.animation.core.Easing
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.SpringSpec
import androidx.compose.animation.core.VectorConverter
@@ -163,9 +164,10 @@
override fun fractionRange(
start: Float?,
end: Float?,
+ easing: Easing,
builder: PropertyTransformationBuilder.() -> Unit
) {
- range = TransformationRange(start, end)
+ range = TransformationRange(start, end, easing)
builder()
range = null
}
@@ -251,6 +253,7 @@
override fun timestampRange(
startMillis: Int?,
endMillis: Int?,
+ easing: Easing,
builder: PropertyTransformationBuilder.() -> Unit
) {
if (startMillis != null && (startMillis < 0 || startMillis > durationMillis)) {
@@ -263,7 +266,7 @@
val start = startMillis?.let { it.toFloat() / durationMillis }
val end = endMillis?.let { it.toFloat() / durationMillis }
- fractionRange(start, end, builder)
+ fractionRange(start, end, easing, builder)
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
index 77ec891..eda8ede 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt
@@ -16,6 +16,8 @@
package com.android.compose.animation.scene.transformation
+import androidx.compose.animation.core.Easing
+import androidx.compose.animation.core.LinearEasing
import androidx.compose.ui.util.fastCoerceAtLeast
import androidx.compose.ui.util.fastCoerceAtMost
import androidx.compose.ui.util.fastCoerceIn
@@ -90,11 +92,13 @@
data class TransformationRange(
val start: Float,
val end: Float,
+ val easing: Easing,
) {
constructor(
start: Float? = null,
- end: Float? = null
- ) : this(start ?: BoundUnspecified, end ?: BoundUnspecified)
+ end: Float? = null,
+ easing: Easing = LinearEasing,
+ ) : this(start ?: BoundUnspecified, end ?: BoundUnspecified, easing)
init {
require(!start.isSpecified() || (start in 0f..1f))
@@ -103,17 +107,20 @@
}
/** Reverse this range. */
- fun reversed() = TransformationRange(start = reverseBound(end), end = reverseBound(start))
+ fun reversed() =
+ TransformationRange(start = reverseBound(end), end = reverseBound(start), easing = easing)
/** Get the progress of this range given the global [transitionProgress]. */
fun progress(transitionProgress: Float): Float {
- return when {
- start.isSpecified() && end.isSpecified() ->
- ((transitionProgress - start) / (end - start)).fastCoerceIn(0f, 1f)
- !start.isSpecified() && !end.isSpecified() -> transitionProgress
- end.isSpecified() -> (transitionProgress / end).fastCoerceAtMost(1f)
- else -> ((transitionProgress - start) / (1f - start)).fastCoerceAtLeast(0f)
- }
+ val progress =
+ when {
+ start.isSpecified() && end.isSpecified() ->
+ ((transitionProgress - start) / (end - start)).fastCoerceIn(0f, 1f)
+ !start.isSpecified() && !end.isSpecified() -> transitionProgress
+ end.isSpecified() -> (transitionProgress / end).fastCoerceAtMost(1f)
+ else -> ((transitionProgress - start) / (1f - start)).fastCoerceAtLeast(0f)
+ }
+ return easing.transform(progress)
}
private fun Float.isSpecified() = this != BoundUnspecified
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
index 68240b5..bed6cef 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -16,6 +16,7 @@
package com.android.compose.animation.scene
+import androidx.compose.animation.core.CubicBezierEasing
import androidx.compose.animation.core.SpringSpec
import androidx.compose.animation.core.TweenSpec
import androidx.compose.animation.core.spring
@@ -107,6 +108,13 @@
fractionRange(start = 0.1f, end = 0.8f) { fade(TestElements.Foo) }
fractionRange(start = 0.2f) { fade(TestElements.Foo) }
fractionRange(end = 0.9f) { fade(TestElements.Foo) }
+ fractionRange(
+ start = 0.1f,
+ end = 0.8f,
+ easing = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+ ) {
+ fade(TestElements.Foo)
+ }
}
}
@@ -118,6 +126,11 @@
TransformationRange(start = 0.1f, end = 0.8f),
TransformationRange(start = 0.2f, end = TransformationRange.BoundUnspecified),
TransformationRange(start = TransformationRange.BoundUnspecified, end = 0.9f),
+ TransformationRange(
+ start = 0.1f,
+ end = 0.8f,
+ CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+ ),
)
}
@@ -130,6 +143,13 @@
timestampRange(startMillis = 100, endMillis = 300) { fade(TestElements.Foo) }
timestampRange(startMillis = 200) { fade(TestElements.Foo) }
timestampRange(endMillis = 400) { fade(TestElements.Foo) }
+ timestampRange(
+ startMillis = 100,
+ endMillis = 300,
+ easing = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+ ) {
+ fade(TestElements.Foo)
+ }
}
}
@@ -141,6 +161,11 @@
TransformationRange(start = 100 / 500f, end = 300 / 500f),
TransformationRange(start = 200 / 500f, end = TransformationRange.BoundUnspecified),
TransformationRange(start = TransformationRange.BoundUnspecified, end = 400 / 500f),
+ TransformationRange(
+ start = 100 / 500f,
+ end = 300 / 500f,
+ easing = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+ ),
)
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/EasingTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/EasingTest.kt
new file mode 100644
index 0000000..07901f2
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/EasingTest.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.compose.animation.scene.transformation
+
+import androidx.compose.animation.core.CubicBezierEasing
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.TestElements
+import com.android.compose.animation.scene.testTransition
+import com.android.compose.test.assertSizeIsEqualTo
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class EasingTest {
+ @get:Rule val rule = createComposeRule()
+
+ @Test
+ fun testFractionRangeEasing() {
+ val easing = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+ rule.testTransition(
+ fromSceneContent = { Box(Modifier.size(100.dp).element(TestElements.Foo)) },
+ toSceneContent = { Box(Modifier.size(100.dp).element(TestElements.Bar)) },
+ transition = {
+ // Scale during 4 frames.
+ spec = tween(16 * 4, easing = LinearEasing)
+ fractionRange(easing = easing) {
+ scaleSize(TestElements.Foo, width = 0f, height = 0f)
+ scaleSize(TestElements.Bar, width = 0f, height = 0f)
+ }
+ },
+ ) {
+ // Foo is entering, is 100dp x 100dp at rest and is scaled by (2, 0.5) during the
+ // transition so it starts at 200dp x 50dp.
+ before { onElement(TestElements.Bar).assertDoesNotExist() }
+ at(0) {
+ onElement(TestElements.Foo).assertSizeIsEqualTo(100.dp, 100.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(0.dp, 0.dp)
+ }
+ at(16) {
+ // 25% linear progress is mapped to 68.5% eased progress
+ onElement(TestElements.Foo).assertSizeIsEqualTo(31.5.dp, 31.5.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(68.5.dp, 68.5.dp)
+ }
+ at(32) {
+ // 50% linear progress is mapped to 89.5% eased progress
+ onElement(TestElements.Foo).assertSizeIsEqualTo(10.5.dp, 10.5.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(89.5.dp, 89.5.dp)
+ }
+ at(48) {
+ // 75% linear progress is mapped to 97.8% eased progress
+ onElement(TestElements.Foo).assertSizeIsEqualTo(2.2.dp, 2.2.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(97.8.dp, 97.8.dp)
+ }
+ after {
+ onElement(TestElements.Foo).assertDoesNotExist()
+ onElement(TestElements.Bar).assertSizeIsEqualTo(100.dp, 100.dp)
+ }
+ }
+ }
+
+ @Test
+ fun testTimestampRangeEasing() {
+ val easing = CubicBezierEasing(0.1f, 0.1f, 0f, 1f)
+ rule.testTransition(
+ fromSceneContent = { Box(Modifier.size(100.dp).element(TestElements.Foo)) },
+ toSceneContent = { Box(Modifier.size(100.dp).element(TestElements.Bar)) },
+ transition = {
+ // Scale during 4 frames.
+ spec = tween(16 * 4, easing = LinearEasing)
+ timestampRange(easing = easing) {
+ scaleSize(TestElements.Foo, width = 0f, height = 0f)
+ scaleSize(TestElements.Bar, width = 0f, height = 0f)
+ }
+ },
+ ) {
+ // Foo is entering, is 100dp x 100dp at rest and is scaled by (2, 0.5) during the
+ // transition so it starts at 200dp x 50dp.
+ before { onElement(TestElements.Bar).assertDoesNotExist() }
+ at(0) {
+ onElement(TestElements.Foo).assertSizeIsEqualTo(100.dp, 100.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(0.dp, 0.dp)
+ }
+ at(16) {
+ // 25% linear progress is mapped to 68.5% eased progress
+ onElement(TestElements.Foo).assertSizeIsEqualTo(31.5.dp, 31.5.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(68.5.dp, 68.5.dp)
+ }
+ at(32) {
+ // 50% linear progress is mapped to 89.5% eased progress
+ onElement(TestElements.Foo).assertSizeIsEqualTo(10.5.dp, 10.5.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(89.5.dp, 89.5.dp)
+ }
+ at(48) {
+ // 75% linear progress is mapped to 97.8% eased progress
+ onElement(TestElements.Foo).assertSizeIsEqualTo(2.2.dp, 2.2.dp)
+ onElement(TestElements.Bar).assertSizeIsEqualTo(97.8.dp, 97.8.dp)
+ }
+ after {
+ onElement(TestElements.Foo).assertDoesNotExist()
+ onElement(TestElements.Bar).assertSizeIsEqualTo(100.dp, 100.dp)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 0242c2d..e57a4cb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -1039,6 +1039,22 @@
assertThat(showCommunalFromOccluded).isTrue()
}
+ @Test
+ fun showCommunalFromOccluded_enteredOccludedFromDreaming() =
+ testScope.runTest {
+ kosmos.setCommunalAvailable(true)
+ val showCommunalFromOccluded by collectLastValue(underTest.showCommunalFromOccluded)
+ assertThat(showCommunalFromOccluded).isFalse()
+
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.DREAMING,
+ to = KeyguardState.OCCLUDED,
+ testScope
+ )
+
+ assertThat(showCommunalFromOccluded).isTrue()
+ }
+
private fun smartspaceTimer(id: String, timestamp: Long = 0L): CommunalSmartspaceTimer {
return CommunalSmartspaceTimer(
smartspaceTargetId = id,
diff --git a/packages/SystemUI/res/layout/media_projection_app_selector.xml b/packages/SystemUI/res/layout/media_projection_app_selector.xml
index b77f78d..3b6a64f 100644
--- a/packages/SystemUI/res/layout/media_projection_app_selector.xml
+++ b/packages/SystemUI/res/layout/media_projection_app_selector.xml
@@ -37,6 +37,7 @@
android:background="@*android:drawable/bottomsheet_background">
<ImageView
+ android:id="@+id/media_projection_app_selector_icon"
android:layout_width="@dimen/media_projection_app_selector_icon_size"
android:layout_height="@dimen/media_projection_app_selector_icon_size"
android:layout_marginTop="@*android:dimen/chooser_edge_margin_normal"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 2ad6b6a..f8303ea 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -291,6 +291,8 @@
<string name="screenrecord_permission_dialog_warning_single_app">When you’re recording an app, anything shown or played in that app is recorded. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
<!-- Button to start a screen recording of the entire screen in the updated screen record dialog that allows to select an app to record [CHAR LIMIT=50]-->
<string name="screenrecord_permission_dialog_continue_entire_screen">Record screen</string>
+ <!-- Title of the activity that allows to select an app to screen record [CHAR LIMIT=70] -->
+ <string name="screenrecord_app_selector_title">Choose app to record</string>
<!-- Label for a switch to enable recording audio [CHAR LIMIT=NONE]-->
<string name="screenrecord_audio_label">Record audio</string>
@@ -1362,8 +1364,8 @@
<!-- Media projection permission dialog warning text for system services. [CHAR LIMIT=NONE] -->
<string name="media_projection_sys_service_dialog_warning">The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.</string>
- <!-- Title of the dialog that allows to select an app to share or record [CHAR LIMIT=NONE] -->
- <string name="screen_share_permission_app_selector_title">Share or record an app</string>
+ <!-- Title of the activity that allows users to select an app to share or record [CHAR LIMIT=NONE] -->
+ <string name="screen_share_generic_app_selector_title">Share or record an app</string>
<!-- Media projection that launched from 1P/3P apps -->
<!-- 1P/3P app media projection permission dialog title. [CHAR LIMIT=NONE] -->
@@ -1381,6 +1383,8 @@
<string name="media_projection_entry_app_permission_dialog_continue_entire_screen">Share screen</string>
<!-- 1P/3P apps disabled the single app projection option. [CHAR LIMIT=NONE] -->
<string name="media_projection_entry_app_permission_dialog_single_app_disabled"><xliff:g id="app_name" example="Meet">%1$s</xliff:g> has disabled this option</string>
+ <!-- Title of the activity that allows users to select an app to share to a 1P/3P app [CHAR LIMIT=70] -->
+ <string name="media_projection_entry_share_app_selector_title">Choose app to share</string>
<!-- Casting that launched by SysUI (i.e. when there is no app name) -->
<!-- System casting media projection permission dialog title. [CHAR LIMIT=100] -->
@@ -1395,6 +1399,8 @@
<string name="media_projection_entry_cast_permission_dialog_warning_single_app">When you’re casting an app, anything shown or played in that app is visible. So be careful with things like passwords, payment details, messages, photos, and audio and video.</string>
<!-- System casting media projection permission button to continue for SysUI casting. [CHAR LIMIT=60] -->
<string name="media_projection_entry_cast_permission_dialog_continue_entire_screen">Cast screen</string>
+ <!-- Title of the activity that allows users to select an app to cast [CHAR LIMIT=70] -->
+ <string name="media_projection_entry_cast_app_selector_title">Choose app to cast</string>
<!-- Other sharing (not recording nor casting) that launched by SysUI (currently not in use) -->
<!-- System sharing media projection permission dialog title. [CHAR LIMIT=100] -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
index 68d2eb3..41ad437 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -26,6 +26,7 @@
import android.graphics.Color;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
@@ -105,8 +106,8 @@
* @return updated set of flags from InputMethodService based off {@param oldHints}
* Leaves original hints unmodified
*/
- public static int calculateBackDispositionHints(int oldHints, int backDisposition,
- boolean imeShown, boolean showImeSwitcher) {
+ public static int calculateBackDispositionHints(int oldHints,
+ @BackDispositionMode int backDisposition, boolean imeShown, boolean showImeSwitcher) {
int hints = oldHints;
switch (backDisposition) {
case InputMethodService.BACK_DISPOSITION_DEFAULT:
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 6aaaf3d..fbeb715 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -184,7 +184,11 @@
keyguardTransitionInteractor.startedKeyguardTransitionStep
.filter { step -> step.to == KeyguardState.OCCLUDED }
.combine(isCommunalAvailable, ::Pair)
- .map { (step, available) -> available && step.from == KeyguardState.GLANCEABLE_HUB }
+ .map { (step, available) ->
+ available &&
+ (step.from == KeyguardState.GLANCEABLE_HUB ||
+ step.from == KeyguardState.DREAMING)
+ }
.flowOn(bgDispatcher)
.stateIn(
scope = applicationScope,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 3273111..79f4568 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -33,6 +33,7 @@
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
import com.android.systemui.doze.DozeHost;
+import com.android.systemui.inputdevice.tutorial.KeyboardTouchpadTutorialModule;
import com.android.systemui.keyboard.shortcut.ShortcutHelperModule;
import com.android.systemui.keyguard.ui.composable.blueprint.DefaultBlueprintModule;
import com.android.systemui.keyguard.ui.view.layout.blueprints.KeyguardBlueprintModule;
@@ -77,7 +78,7 @@
import com.android.systemui.statusbar.policy.SensorPrivacyController;
import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
import com.android.systemui.toast.ToastModule;
-import com.android.systemui.touchpad.tutorial.TouchpadKeyboardTutorialModule;
+import com.android.systemui.touchpad.tutorial.TouchpadTutorialModule;
import com.android.systemui.unfold.SysUIUnfoldStartableModule;
import com.android.systemui.unfold.UnfoldTransitionModule;
import com.android.systemui.util.kotlin.SysUICoroutinesModule;
@@ -122,6 +123,7 @@
KeyboardShortcutsModule.class,
KeyguardBlueprintModule.class,
KeyguardSectionsModule.class,
+ KeyboardTouchpadTutorialModule.class,
MediaModule.class,
MediaMuteAwaitConnectionCli.StartableModule.class,
MultiUserUtilsModule.class,
@@ -142,7 +144,7 @@
SysUIUnfoldStartableModule.class,
UnfoldTransitionModule.Startables.class,
ToastModule.class,
- TouchpadKeyboardTutorialModule.class,
+ TouchpadTutorialModule.class,
VolumeModule.class,
WallpaperModule.class,
ShortcutHelperModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index b0f2c18..cbea876 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -258,13 +258,6 @@
@Binds
@IntoMap
- @ClassKey(KeyboardTouchpadTutorialCoreStartable::class)
- abstract fun bindKeyboardTouchpadTutorialCoreStartable(
- listener: KeyboardTouchpadTutorialCoreStartable
- ): CoreStartable
-
- @Binds
- @IntoMap
@ClassKey(PhysicalKeyboardCoreStartable::class)
abstract fun bindKeyboardCoreStartable(listener: PhysicalKeyboardCoreStartable): CoreStartable
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/KeyboardTouchpadTutorialModule.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/KeyboardTouchpadTutorialModule.kt
new file mode 100644
index 0000000..8e6cb07
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/KeyboardTouchpadTutorialModule.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 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.systemui.inputdevice.tutorial
+
+import android.app.Activity
+import com.android.systemui.CoreStartable
+import com.android.systemui.inputdevice.tutorial.ui.view.KeyboardTouchpadTutorialActivity
+import com.android.systemui.touchpad.tutorial.domain.interactor.TouchpadGesturesInteractor
+import dagger.Binds
+import dagger.BindsOptionalOf
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+interface KeyboardTouchpadTutorialModule {
+
+ @Binds
+ @IntoMap
+ @ClassKey(KeyboardTouchpadTutorialCoreStartable::class)
+ fun bindKeyboardTouchpadTutorialCoreStartable(
+ listener: KeyboardTouchpadTutorialCoreStartable
+ ): CoreStartable
+
+ @Binds
+ @IntoMap
+ @ClassKey(KeyboardTouchpadTutorialActivity::class)
+ fun activity(impl: KeyboardTouchpadTutorialActivity): Activity
+
+ // TouchpadModule dependencies below
+ // all should be optional to not introduce touchpad dependency in all sysui variants
+
+ @BindsOptionalOf fun touchpadScreensProvider(): TouchpadTutorialScreensProvider
+
+ @BindsOptionalOf fun touchpadGesturesInteractor(): TouchpadGesturesInteractor
+}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/TouchpadTutorialScreensProvider.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/TouchpadTutorialScreensProvider.kt
new file mode 100644
index 0000000..bd3e771
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/TouchpadTutorialScreensProvider.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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.systemui.inputdevice.tutorial
+
+import androidx.compose.runtime.Composable
+
+interface TouchpadTutorialScreensProvider {
+
+ @Composable fun BackGesture(onDoneButtonClicked: () -> Unit, onBack: () -> Unit)
+
+ @Composable fun HomeGesture(onDoneButtonClicked: () -> Unit, onBack: () -> Unit)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/ActionKeyTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/ActionKeyTutorialScreen.kt
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/ActionKeyTutorialScreen.kt
rename to packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/ActionKeyTutorialScreen.kt
index f7f2631..c5b0ca7 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/ActionKeyTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/ActionKeyTutorialScreen.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.touchpad.tutorial.ui.composable
+package com.android.systemui.inputdevice.tutorial.ui.composable
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Box
@@ -34,9 +34,9 @@
import androidx.compose.ui.input.key.type
import com.airbnb.lottie.compose.rememberLottieDynamicProperties
import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.FINISHED
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.NOT_STARTED
import com.android.systemui.res.R
-import com.android.systemui.touchpad.tutorial.ui.composable.TutorialActionState.FINISHED
-import com.android.systemui.touchpad.tutorial.ui.composable.TutorialActionState.NOT_STARTED
@Composable
fun ActionKeyTutorialScreen(
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/ActionTutorialContent.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/ActionTutorialContent.kt
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/ActionTutorialContent.kt
rename to packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/ActionTutorialContent.kt
index 2b7f674..c50b7dc 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/ActionTutorialContent.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/ActionTutorialContent.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.touchpad.tutorial.ui.composable
+package com.android.systemui.inputdevice.tutorial.ui.composable
import android.graphics.ColorFilter
import android.graphics.PorterDuff
@@ -60,9 +60,9 @@
import com.airbnb.lottie.compose.animateLottieCompositionAsState
import com.airbnb.lottie.compose.rememberLottieComposition
import com.airbnb.lottie.compose.rememberLottieDynamicProperty
-import com.android.systemui.touchpad.tutorial.ui.composable.TutorialActionState.FINISHED
-import com.android.systemui.touchpad.tutorial.ui.composable.TutorialActionState.IN_PROGRESS
-import com.android.systemui.touchpad.tutorial.ui.composable.TutorialActionState.NOT_STARTED
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.FINISHED
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.IN_PROGRESS
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.NOT_STARTED
enum class TutorialActionState {
NOT_STARTED,
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialComponents.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/TutorialComponents.kt
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialComponents.kt
rename to packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/TutorialComponents.kt
index f2276c8..01ad585 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialComponents.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/TutorialComponents.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.touchpad.tutorial.ui.composable
+package com.android.systemui.inputdevice.tutorial.ui.composable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialScreenConfig.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/TutorialScreenConfig.kt
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialScreenConfig.kt
rename to packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/TutorialScreenConfig.kt
index d76ceb9..0406bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialScreenConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/composable/TutorialScreenConfig.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.touchpad.tutorial.ui.composable
+package com.android.systemui.inputdevice.tutorial.ui.composable
import androidx.annotation.RawRes
import androidx.annotation.StringRes
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/view/KeyboardTouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/view/KeyboardTouchpadTutorialActivity.kt
new file mode 100644
index 0000000..3e382d6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/view/KeyboardTouchpadTutorialActivity.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 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.systemui.inputdevice.tutorial.ui.view
+
+import android.os.Bundle
+import android.view.WindowManager
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.activity.viewModels
+import androidx.compose.runtime.Composable
+import com.android.compose.theme.PlatformTheme
+import com.android.systemui.inputdevice.tutorial.TouchpadTutorialScreensProvider
+import com.android.systemui.inputdevice.tutorial.ui.viewmodel.KeyboardTouchpadTutorialViewModel
+import java.util.Optional
+import javax.inject.Inject
+
+/**
+ * Activity for out of the box experience for keyboard and touchpad. Note that it's possible that
+ * either of them are actually not connected when this is launched
+ */
+class KeyboardTouchpadTutorialActivity
+@Inject
+constructor(
+ private val viewModelFactory: KeyboardTouchpadTutorialViewModel.Factory,
+ private val touchpadTutorialScreensProvider: Optional<TouchpadTutorialScreensProvider>,
+) : ComponentActivity() {
+
+ private val vm by
+ viewModels<KeyboardTouchpadTutorialViewModel>(factoryProducer = { viewModelFactory })
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ setContent {
+ PlatformTheme {
+ KeyboardTouchpadTutorialContainer(vm, touchpadTutorialScreensProvider) { finish() }
+ }
+ }
+ // required to handle 3+ fingers on touchpad
+ window.addPrivateFlags(WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY)
+ }
+
+ override fun onResume() {
+ super.onResume()
+ vm.onOpened()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ vm.onClosed()
+ }
+}
+
+@Composable
+fun KeyboardTouchpadTutorialContainer(
+ vm: KeyboardTouchpadTutorialViewModel,
+ touchpadTutorialScreensProvider: Optional<TouchpadTutorialScreensProvider>,
+ closeTutorial: () -> Unit
+) {}
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt
new file mode 100644
index 0000000..39b1ec0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/oobe/ui/viewmodel/KeyboardTouchpadTutorialViewModel.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 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.systemui.inputdevice.tutorial.ui.viewmodel
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.android.systemui.touchpad.tutorial.domain.interactor.TouchpadGesturesInteractor
+import java.util.Optional
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class KeyboardTouchpadTutorialViewModel(
+ private val gesturesInteractor: Optional<TouchpadGesturesInteractor>
+) : ViewModel() {
+
+ private val _screen = MutableStateFlow(Screen.BACK_GESTURE)
+ val screen: StateFlow<Screen> = _screen
+
+ fun goTo(screen: Screen) {
+ _screen.value = screen
+ }
+
+ fun onOpened() {
+ gesturesInteractor.ifPresent { it.disableGestures() }
+ }
+
+ fun onClosed() {
+ gesturesInteractor.ifPresent { it.enableGestures() }
+ }
+
+ class Factory
+ @Inject
+ constructor(private val gesturesInteractor: Optional<TouchpadGesturesInteractor>) :
+ ViewModelProvider.Factory {
+
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ return KeyboardTouchpadTutorialViewModel(gesturesInteractor) as T
+ }
+ }
+}
+
+enum class Screen {
+ BACK_GESTURE,
+ HOME_GESTURE,
+ ACTION_KEY
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 1f3df95..17c5977 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -42,6 +42,7 @@
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.Flags.notifyPowerManagerUserActivityBackground;
import static com.android.systemui.Flags.refactorGetCurrentUser;
+import static com.android.systemui.Flags.relockWithPowerButtonImmediately;
import static com.android.systemui.Flags.translucentOccludingActivityFix;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
@@ -477,6 +478,7 @@
private boolean mUnlockingAndWakingFromDream = false;
private boolean mHideAnimationRun = false;
private boolean mHideAnimationRunning = false;
+ private boolean mIsKeyguardExitAnimationCanceled = false;
private SoundPool mLockSounds;
private int mLockSoundId;
@@ -1588,10 +1590,11 @@
setShowingLocked(!shouldWaitForProvisioning()
&& !mLockPatternUtils.isLockScreenDisabled(
mSelectedUserInteractor.getSelectedUserId()),
- true /* forceCallbacks */);
+ true /* forceCallbacks */, "setupLocked - keyguard service enabled");
} else {
// The system's keyguard is disabled or missing.
- setShowingLocked(false /* showing */, true /* forceCallbacks */);
+ setShowingLocked(false /* showing */, true /* forceCallbacks */,
+ "setupLocked - keyguard service disabled");
}
mKeyguardTransitions.register(
@@ -2833,9 +2836,10 @@
playSound(mTrustedSoundId);
}
- private void updateActivityLockScreenState(boolean showing, boolean aodShowing) {
+ private void updateActivityLockScreenState(boolean showing, boolean aodShowing, String reason) {
mUiBgExecutor.execute(() -> {
- Log.d(TAG, "updateActivityLockScreenState(" + showing + ", " + aodShowing + ")");
+ Log.d(TAG, "updateActivityLockScreenState(" + showing + ", " + aodShowing + ", "
+ + reason + ")");
if (KeyguardWmStateRefactor.isEnabled()) {
// Handled in WmLockscreenVisibilityManager if flag is enabled.
@@ -2895,7 +2899,7 @@
// Force if we're showing in the middle of unlocking, to ensure we end up in the
// correct state.
- setShowingLocked(true, hidingOrGoingAway /* force */);
+ setShowingLocked(true, hidingOrGoingAway /* force */, "handleShowInner");
mHiding = false;
if (!KeyguardWmStateRefactor.isEnabled()) {
@@ -3067,15 +3071,14 @@
mHiding = true;
mKeyguardGoingAwayRunnable.run();
} else {
- Log.d(TAG, "Hiding keyguard while occluded. Just hide the keyguard view and exit.");
-
if (!KeyguardWmStateRefactor.isEnabled()) {
mKeyguardViewControllerLazy.get().hide(
mSystemClock.uptimeMillis() + mHideAnimation.getStartOffset(),
mHideAnimation.getDuration());
}
- onKeyguardExitFinished();
+ onKeyguardExitFinished("Hiding keyguard while occluded. Just hide the keyguard "
+ + "view and exit.");
}
// It's possible that the device was unlocked (via BOUNCER or Fingerprint) while
@@ -3106,6 +3109,7 @@
Log.d(TAG, "handleStartKeyguardExitAnimation startTime=" + startTime
+ " fadeoutDuration=" + fadeoutDuration);
synchronized (KeyguardViewMediator.this) {
+ mIsKeyguardExitAnimationCanceled = false;
// Tell ActivityManager that we canceled the keyguard animation if
// handleStartKeyguardExitAnimation was called, but we're not hiding the keyguard,
// unless we're animating the surface behind the keyguard and will be hiding the
@@ -3125,7 +3129,8 @@
Slog.w(TAG, "Failed to call onAnimationFinished", e);
}
}
- setShowingLocked(mShowing, true /* force */);
+ setShowingLocked(mShowing, true /* force */,
+ "handleStartKeyguardExitAnimation - canceled");
return;
}
mHiding = false;
@@ -3149,9 +3154,11 @@
Slog.w(TAG, "Failed to call onAnimationFinished", e);
}
}
- onKeyguardExitFinished();
- mKeyguardViewControllerLazy.get().hide(0 /* startTime */,
- 0 /* fadeoutDuration */);
+ if (!mIsKeyguardExitAnimationCanceled) {
+ onKeyguardExitFinished("onRemoteAnimationFinished");
+ mKeyguardViewControllerLazy.get().hide(0 /* startTime */,
+ 0 /* fadeoutDuration */);
+ }
mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
}
@@ -3288,12 +3295,12 @@
anim.start();
});
- onKeyguardExitFinished();
+ onKeyguardExitFinished("remote animation disabled");
}
}
}
- private void onKeyguardExitFinished() {
+ private void onKeyguardExitFinished(String reason) {
if (DEBUG) Log.d(TAG, "onKeyguardExitFinished()");
// only play "unlock" noises if not on a call (since the incall UI
// disables the keyguard)
@@ -3301,7 +3308,7 @@
playSounds(false);
}
- setShowingLocked(false);
+ setShowingLocked(false, "onKeyguardExitFinished: " + reason);
mWakeAndUnlocking = false;
mDismissCallbackRegistry.notifyDismissSucceeded();
resetKeyguardDonePendingLocked();
@@ -3349,6 +3356,9 @@
// A lock is pending, meaning the keyguard exit animation was cancelled because we're
// re-locking. We should just end the surface-behind animation without exiting the
// keyguard. The pending lock will be handled by onFinishedGoingToSleep().
+ if (relockWithPowerButtonImmediately()) {
+ mIsKeyguardExitAnimationCanceled = true;
+ }
finishSurfaceBehindRemoteAnimation(true /* showKeyguard */);
maybeHandlePendingLock();
} else {
@@ -3397,12 +3407,13 @@
doKeyguardLocked(null);
finishSurfaceBehindRemoteAnimation(true /* showKeyguard */);
// Ensure WM is notified that we made a decision to show
- setShowingLocked(true /* showing */, true /* force */);
+ setShowingLocked(true /* showing */, true /* force */,
+ "exitKeyguardAndFinishSurfaceBehindRemoteAnimation - relocked");
return;
}
- onKeyguardExitFinished();
+ onKeyguardExitFinished("exitKeyguardAndFinishSurfaceBehindRemoteAnimation");
if (mKeyguardStateController.isDismissingFromSwipe() || wasShowing) {
Log.d(TAG, "onKeyguardExitRemoteAnimationFinished"
@@ -3459,7 +3470,7 @@
mSurfaceBehindRemoteAnimationRequested = false;
mKeyguardStateController.notifyKeyguardGoingAway(false);
if (mShowing) {
- setShowingLocked(true, true);
+ setShowingLocked(true, true, "hideSurfaceBehindKeyguard");
}
}
@@ -3805,7 +3816,7 @@
// update lock screen state in ATMS here, otherwise ATMS tries to resume activities when
// enabling doze state.
if (mShowing || !mPendingLock || !mDozeParameters.canControlUnlockedScreenOff()) {
- setShowingLocked(mShowing);
+ setShowingLocked(mShowing, "setDozing");
}
}
@@ -3815,7 +3826,7 @@
// is 1f), then show the activity lock screen.
if (mAnimatingScreenOff && mDozing && linear == 1f) {
mAnimatingScreenOff = false;
- setShowingLocked(mShowing, true);
+ setShowingLocked(mShowing, true, "onDozeAmountChanged");
}
}
@@ -3853,11 +3864,11 @@
}
}
- void setShowingLocked(boolean showing) {
- setShowingLocked(showing, false /* forceCallbacks */);
+ void setShowingLocked(boolean showing, String reason) {
+ setShowingLocked(showing, false /* forceCallbacks */, reason);
}
- private void setShowingLocked(boolean showing, boolean forceCallbacks) {
+ private void setShowingLocked(boolean showing, boolean forceCallbacks, String reason) {
final boolean aodShowing = mDozing && !mWakeAndUnlocking;
final boolean notifyDefaultDisplayCallbacks = showing != mShowing || forceCallbacks;
final boolean updateActivityLockScreenState = showing != mShowing
@@ -3868,9 +3879,8 @@
notifyDefaultDisplayCallbacks(showing);
}
if (updateActivityLockScreenState) {
- updateActivityLockScreenState(showing, aodShowing);
+ updateActivityLockScreenState(showing, aodShowing, reason);
}
-
}
private void notifyDefaultDisplayCallbacks(boolean showing) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/OWNERS b/packages/SystemUI/src/com/android/systemui/keyguard/OWNERS
new file mode 100644
index 0000000..443e9876
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/OWNERS
@@ -0,0 +1,11 @@
+set noparent
+
+# Bug component: 78010
+
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
index d6affd2..228b576 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
@@ -32,6 +32,10 @@
import android.view.View
import android.view.ViewGroup
import android.view.accessibility.AccessibilityEvent
+import android.widget.ImageView
+import androidx.annotation.ColorRes
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
@@ -52,6 +56,7 @@
import com.android.systemui.res.R
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.AsyncActivityLauncher
+import java.lang.IllegalArgumentException
import javax.inject.Inject
class MediaProjectionAppSelectorActivity(
@@ -116,6 +121,7 @@
super.onCreate(savedInstanceState)
controller.init()
+ setIcon()
// we override AppList's AccessibilityDelegate set in ResolverActivity.onCreate because in
// our case this delegate must extend RecyclerViewAccessibilityDelegate, otherwise
// RecyclerView scrolling is broken
@@ -298,6 +304,29 @@
override fun createContentPreviewView(parent: ViewGroup): ViewGroup =
recentsViewController.createView(parent)
+ /** Set up intent for the [ChooserActivity] */
+ private fun Intent.configureChooserIntent(
+ resources: Resources,
+ hostUserHandle: UserHandle,
+ personalProfileUserHandle: UserHandle,
+ ) {
+ // Specify the query intent to show icons for all apps on the chooser screen
+ val queryIntent = Intent(Intent.ACTION_MAIN).apply { addCategory(Intent.CATEGORY_LAUNCHER) }
+ putExtra(Intent.EXTRA_INTENT, queryIntent)
+
+ // Update the title of the chooser
+ putExtra(Intent.EXTRA_TITLE, resources.getString(titleResId))
+
+ // Select host app's profile tab by default
+ val selectedProfile =
+ if (hostUserHandle == personalProfileUserHandle) {
+ PROFILE_PERSONAL
+ } else {
+ PROFILE_WORK
+ }
+ putExtra(EXTRA_SELECTED_PROFILE, selectedProfile)
+ }
+
private val hostUserHandle: UserHandle
get() {
val extras =
@@ -321,6 +350,54 @@
return intent.getIntExtra(EXTRA_HOST_APP_UID, /* defaultValue= */ -1)
}
+ /**
+ * The type of screen sharing being performed. Used to show the right text and icon in the
+ * activity.
+ */
+ private val screenShareType: ScreenShareType?
+ get() {
+ if (!intent.hasExtra(EXTRA_SCREEN_SHARE_TYPE)) {
+ return null
+ } else {
+ val type = intent.getStringExtra(EXTRA_SCREEN_SHARE_TYPE) ?: return null
+ return try {
+ enumValueOf<ScreenShareType>(type)
+ } catch (e: IllegalArgumentException) {
+ null
+ }
+ }
+ }
+
+ @get:StringRes
+ private val titleResId: Int
+ get() =
+ when (screenShareType) {
+ ScreenShareType.ShareToApp ->
+ R.string.media_projection_entry_share_app_selector_title
+ ScreenShareType.SystemCast ->
+ R.string.media_projection_entry_cast_app_selector_title
+ ScreenShareType.ScreenRecord -> R.string.screenrecord_app_selector_title
+ null -> R.string.screen_share_generic_app_selector_title
+ }
+
+ @get:DrawableRes
+ private val iconResId: Int
+ get() =
+ when (screenShareType) {
+ ScreenShareType.ShareToApp -> R.drawable.ic_present_to_all
+ ScreenShareType.SystemCast -> R.drawable.ic_cast_connected
+ ScreenShareType.ScreenRecord -> R.drawable.ic_screenrecord
+ null -> R.drawable.ic_present_to_all
+ }
+
+ @get:ColorRes
+ private val iconTintResId: Int?
+ get() =
+ when (screenShareType) {
+ ScreenShareType.ScreenRecord -> R.color.screenrecord_icon_color
+ else -> null
+ }
+
companion object {
const val TAG = "MediaProjectionAppSelectorActivity"
@@ -343,30 +420,18 @@
const val EXTRA_HOST_APP_UID = "launched_from_host_uid"
const val KEY_CAPTURE_TARGET = "capture_region"
- /** Set up intent for the [ChooserActivity] */
- private fun Intent.configureChooserIntent(
- resources: Resources,
- hostUserHandle: UserHandle,
- personalProfileUserHandle: UserHandle
- ) {
- // Specify the query intent to show icons for all apps on the chooser screen
- val queryIntent =
- Intent(Intent.ACTION_MAIN).apply { addCategory(Intent.CATEGORY_LAUNCHER) }
- putExtra(Intent.EXTRA_INTENT, queryIntent)
+ /**
+ * The type of screen sharing being performed.
+ *
+ * The value set for this extra should match the name of a [ScreenShareType].
+ */
+ const val EXTRA_SCREEN_SHARE_TYPE = "screen_share_type"
+ }
- // Update the title of the chooser
- val title = resources.getString(R.string.screen_share_permission_app_selector_title)
- putExtra(Intent.EXTRA_TITLE, title)
-
- // Select host app's profile tab by default
- val selectedProfile =
- if (hostUserHandle == personalProfileUserHandle) {
- PROFILE_PERSONAL
- } else {
- PROFILE_WORK
- }
- putExtra(EXTRA_SELECTED_PROFILE, selectedProfile)
- }
+ private fun setIcon() {
+ val iconView = findViewById<ImageView>(R.id.media_projection_app_selector_icon) ?: return
+ iconView.setImageResource(iconResId)
+ iconTintResId?.let { iconView.setColorFilter(this.resources.getColor(it, this.theme)) }
}
private fun setAppListAccessibilityDelegate() {
@@ -406,4 +471,14 @@
return delegate.onRequestSendAccessibilityEvent(host, child, event)
}
}
+
+ /** Enum describing what type of app screen sharing is being performed. */
+ enum class ScreenShareType {
+ /** The selected app will be cast to another device. */
+ SystemCast,
+ /** The selected app will be shared to another app on the device. */
+ ShareToApp,
+ /** The selected app will be recorded. */
+ ScreenRecord,
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 3c83db3..18c6f53 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -73,8 +73,7 @@
import dagger.Lazy;
-public class MediaProjectionPermissionActivity extends Activity
- implements DialogInterface.OnClickListener {
+public class MediaProjectionPermissionActivity extends Activity {
private static final String TAG = "MediaProjectionPermissionActivity";
private static final float MAX_APP_NAME_SIZE_PX = 500f;
private static final String ELLIPSIS = "\u2026";
@@ -269,7 +268,8 @@
Consumer<BaseMediaProjectionPermissionDialogDelegate<AlertDialog>> onStartRecordingClicked =
dialog -> {
ScreenShareOption selectedOption = dialog.getSelectedScreenShareOption();
- grantMediaProjectionPermission(selectedOption.getMode());
+ grantMediaProjectionPermission(
+ selectedOption.getMode(), hasCastingCapabilities);
};
Runnable onCancelClicked = () -> finish(RECORD_CANCEL, /* projection= */ null);
if (hasCastingCapabilities) {
@@ -305,19 +305,6 @@
}
}
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (which == AlertDialog.BUTTON_POSITIVE) {
- grantMediaProjectionPermission(ENTIRE_SCREEN);
- } else {
- if (mDialog != null) {
- mDialog.dismiss();
- }
- setResult(RESULT_CANCELED);
- finish(RECORD_CANCEL, /* projection= */ null);
- }
- }
-
private void setUpDialog(AlertDialog dialog) {
SystemUIDialog.registerDismissListener(dialog);
SystemUIDialog.applyFlags(dialog);
@@ -345,25 +332,21 @@
return false;
}
- private void grantMediaProjectionPermission(int screenShareMode) {
+ private void grantMediaProjectionPermission(
+ int screenShareMode, boolean hasCastingCapabilities) {
try {
+ IMediaProjection projection = MediaProjectionServiceHelper.createOrReuseProjection(
+ mUid, mPackageName, mReviewGrantedConsentRequired);
if (screenShareMode == ENTIRE_SCREEN) {
- final IMediaProjection projection =
- MediaProjectionServiceHelper.createOrReuseProjection(mUid, mPackageName,
- mReviewGrantedConsentRequired);
final Intent intent = new Intent();
- intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
- projection.asBinder());
+ setCommonIntentExtras(intent, hasCastingCapabilities, projection);
setResult(RESULT_OK, intent);
finish(RECORD_CONTENT_DISPLAY, projection);
}
if (screenShareMode == SINGLE_APP) {
- IMediaProjection projection = MediaProjectionServiceHelper.createOrReuseProjection(
- mUid, mPackageName, mReviewGrantedConsentRequired);
final Intent intent = new Intent(this,
MediaProjectionAppSelectorActivity.class);
- intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
- projection.asBinder());
+ setCommonIntentExtras(intent, hasCastingCapabilities, projection);
intent.putExtra(MediaProjectionAppSelectorActivity.EXTRA_HOST_APP_USER_HANDLE,
getHostUserHandle());
intent.putExtra(
@@ -391,6 +374,19 @@
}
}
+ private void setCommonIntentExtras(
+ Intent intent,
+ boolean hasCastingCapabilities,
+ IMediaProjection projection) throws RemoteException {
+ intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
+ projection.asBinder());
+ intent.putExtra(
+ MediaProjectionAppSelectorActivity.EXTRA_SCREEN_SHARE_TYPE,
+ hasCastingCapabilities
+ ? MediaProjectionAppSelectorActivity.ScreenShareType.SystemCast.name()
+ : MediaProjectionAppSelectorActivity.ScreenShareType.ShareToApp.name());
+ }
+
private UserHandle getHostUserHandle() {
return UserHandle.getUserHandleForUid(getLaunchedFromUid());
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index 13a786a..ac878c2 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -38,6 +38,7 @@
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -516,7 +517,7 @@
* @return Whether the IME is shown on top of the screen given the {@code vis} flag of
* {@link InputMethodService} and the keyguard states.
*/
- public boolean isImeShown(int vis) {
+ public boolean isImeShown(@ImeWindowVisibility int vis) {
View shadeWindowView = mNotificationShadeWindowController.getWindowRootView();
boolean isKeyguardShowing = mKeyguardStateController.isShowing();
boolean imeVisibleOnShade = shadeWindowView != null && shadeWindowView.isAttachedToWindow()
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 15b1e4d..cb0bb4a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -42,6 +42,8 @@
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
@@ -424,8 +426,8 @@
}
@Override
- public void setImeWindowStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
boolean imeShown = mNavBarHelper.isImeShown(vis);
if (!imeShown) {
// Count imperceptible changes as visible so we transition taskbar out quickly.
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
index e895d83..c706c3e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
@@ -68,6 +68,8 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -1098,8 +1100,8 @@
// ----- CommandQueue Callbacks -----
@Override
- public void setImeWindowStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
if (displayId != mDisplayId) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 9939075..1511f31 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -259,6 +259,13 @@
}
/**
+ * @return height with the squishiness fraction applied.
+ */
+ int getSquishedQqsHeight() {
+ return mHeader.getSquishedHeight();
+ }
+
+ /**
* Returns the size of QS (or the QSCustomizer), regardless of the measured size of this view
* @return size in pixels of QS (or QSCustomizer)
*/
@@ -267,6 +274,13 @@
: mQSPanel.getMeasuredHeight();
}
+ /**
+ * @return height with the squishiness fraction applied.
+ */
+ int getSquishedQsHeight() {
+ return mQSPanel.getSquishedHeight();
+ }
+
public void setExpansion(float expansion) {
mQsExpansion = expansion;
if (mQSPanelContainer != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
index a6fd35a..0b37b5b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
@@ -992,11 +992,25 @@
return mContainer.getQqsHeight();
}
+ /**
+ * @return height with the squishiness fraction applied.
+ */
+ public int getSquishedQqsHeight() {
+ return mContainer.getSquishedQqsHeight();
+ }
+
public int getQSHeight() {
return mContainer.getQsHeight();
}
/**
+ * @return height with the squishiness fraction applied.
+ */
+ public int getSquishedQsHeight() {
+ return mContainer.getSquishedQsHeight();
+ }
+
+ /**
* Pass the size of the navbar when it's at the bottom of the device so it can be used as
* padding
* @param padding size of the bottom nav bar in px
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 032891f..d3bed27 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -733,6 +733,30 @@
mCanCollapse = canCollapse;
}
+ /**
+ * @return height with the {@link QSPanel#setSquishinessFraction(float)} applied.
+ */
+ public int getSquishedHeight() {
+ if (mFooter != null) {
+ final ViewGroup.LayoutParams footerLayoutParams = mFooter.getLayoutParams();
+ final int footerBottomMargin;
+ if (footerLayoutParams instanceof MarginLayoutParams) {
+ footerBottomMargin = ((MarginLayoutParams) footerLayoutParams).bottomMargin;
+ } else {
+ footerBottomMargin = 0;
+ }
+ // This is the distance between the top of the QSPanel and the last view in the
+ // layout (which is the effective the bottom)
+ return mFooter.getBottom() + footerBottomMargin - getTop();
+ }
+ if (mTileLayout != null) {
+ // Footer absence means that the panel is in the QQS. In this case it's just height
+ // of the tiles + paddings.
+ return mTileLayout.getTilesHeight() + getPaddingBottom() + getPaddingTop();
+ }
+ return getHeight();
+ }
+
@Nullable
@VisibleForTesting
View getMediaPlaceholder() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 5a3f1c0..8fde52c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -123,4 +123,11 @@
lp.setMarginEnd(marginEnd);
view.setLayoutParams(lp);
}
+
+ /**
+ * @return height with the squishiness fraction applied.
+ */
+ public int getSquishedHeight() {
+ return mHeaderQsPanel.getSquishedHeight();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
index ae2f32a..dfcf216 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
@@ -34,7 +34,6 @@
import com.android.systemui.qs.QSContainerImpl
import com.android.systemui.qs.QSImpl
import com.android.systemui.qs.dagger.QSSceneComponent
-import com.android.systemui.qs.tiles.viewmodel.StubQSTileViewModel.state
import com.android.systemui.res.R
import com.android.systemui.settings.brightness.MirrorController
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -126,12 +125,18 @@
/** The current height of QQS in the current [qsView], or 0 if there's no view. */
val qqsHeight: Int
+ /** @return height with the squishiness fraction applied. */
+ val squishedQqsHeight: Int
+
/**
* The current height of QS in the current [qsView], or 0 if there's no view. If customizing, it
* will return the height allocated to the customizer.
*/
val qsHeight: Int
+ /** @return height with the squishiness fraction applied. */
+ val squishedQsHeight: Int
+
/** Compatibility for use by LockscreenShadeTransitionController. Matches default from [QS] */
val isQsFullyCollapsed: Boolean
get() = true
@@ -273,9 +278,15 @@
override val qqsHeight: Int
get() = qsImpl.value?.qqsHeight ?: 0
+ override val squishedQqsHeight: Int
+ get() = qsImpl.value?.squishedQqsHeight ?: 0
+
override val qsHeight: Int
get() = qsImpl.value?.qsHeight ?: 0
+ override val squishedQsHeight: Int
+ get() = qsImpl.value?.squishedQsHeight ?: 0
+
// If value is null, there's no QS and therefore it's fully collapsed.
override val isQsFullyCollapsed: Boolean
get() = qsImpl.value?.isFullyCollapsed ?: true
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
index 46ac54f..f3357ee 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialogDelegate.kt
@@ -146,6 +146,10 @@
hostUserHandle
)
intent.putExtra(MediaProjectionAppSelectorActivity.EXTRA_HOST_APP_UID, hostUid)
+ intent.putExtra(
+ MediaProjectionAppSelectorActivity.EXTRA_SCREEN_SHARE_TYPE,
+ MediaProjectionAppSelectorActivity.ScreenShareType.ScreenRecord.name,
+ )
activityStarter.startActivity(intent, /* dismissShade= */ true)
}
dialog.dismiss()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 50be6dc..a1477b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -37,6 +37,7 @@
import android.hardware.biometrics.PromptInfo;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.media.INearbyMediaDevicesProvider;
import android.media.MediaRoute2Info;
import android.os.Binder;
@@ -257,10 +258,10 @@
*
* @param displayId The id of the display to notify.
* @param vis IME visibility.
- * @param backDisposition Disposition mode of back button. It should be one of below flags:
+ * @param backDisposition Disposition mode of back button.
* @param showImeSwitcher {@code true} to show IME switch button.
*/
- default void setImeWindowStatus(int displayId, int vis,
+ default void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
@BackDispositionMode int backDisposition, boolean showImeSwitcher) { }
default void showRecentApps(boolean triggeredFromAltTab) { }
default void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
@@ -743,8 +744,8 @@
}
@Override
- public void setImeWindowStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
synchronized (mLock) {
mHandler.removeMessages(MSG_SHOW_IME_BUTTON);
SomeArgs args = SomeArgs.obtain();
@@ -1205,8 +1206,8 @@
}
}
- private void handleShowImeButton(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ private void handleShowImeButton(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
if (displayId == INVALID_DISPLAY) return;
boolean isConcurrentMultiUserModeEnabled = UserManager.isVisibleBackgroundUsersEnabled()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
index 69ebb76..c4f539a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OWNERS
@@ -5,3 +5,12 @@
[email protected]
[email protected]
[email protected]
+
+per-file *Biometrics* = set noparent
+per-file *Biometrics* = file:../keyguard/OWNERS
+per-file *Doze* = set noparent
+per-file *Doze* = file:../keyguard/OWNERS
+per-file *Keyboard* = set noparent
+per-file *Keyboard* = file:../keyguard/OWNERS
+per-file *Keyguard* = set noparent
+per-file *Keyguard* = file:../keyguard/OWNERS
\ No newline at end of file
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 ada3c52..c4fbc37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -30,6 +30,7 @@
import static com.android.systemui.Flags.keyboardShortcutHelperRewrite;
import static com.android.systemui.Flags.lightRevealMigration;
import static com.android.systemui.Flags.newAodTransition;
+import static com.android.systemui.Flags.relockWithPowerButtonImmediately;
import static com.android.systemui.charging.WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL;
import static com.android.systemui.flags.Flags.SHORTCUT_LIST_SEARCH_LAYOUT;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
@@ -2352,11 +2353,13 @@
} else if (mState == StatusBarState.KEYGUARD
&& !mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()
&& mStatusBarKeyguardViewManager.isSecure()) {
- Log.d(TAG, "showBouncerOrLockScreenIfKeyguard, showingBouncer");
- if (SceneContainerFlag.isEnabled()) {
- mStatusBarKeyguardViewManager.showPrimaryBouncer(true /* scrimmed */);
- } else {
- mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
+ if (!relockWithPowerButtonImmediately()) {
+ Log.d(TAG, "showBouncerOrLockScreenIfKeyguard, showingBouncer");
+ if (SceneContainerFlag.isEnabled()) {
+ mStatusBarKeyguardViewManager.showPrimaryBouncer(true /* scrimmed */);
+ } else {
+ mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadKeyboardTutorialModule.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadKeyboardTutorialModule.kt
deleted file mode 100644
index 8ba8db4..0000000
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadKeyboardTutorialModule.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2024 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.systemui.touchpad.tutorial
-
-import android.app.Activity
-import com.android.systemui.touchpad.tutorial.ui.view.TouchpadTutorialActivity
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
-
-@Module
-interface TouchpadKeyboardTutorialModule {
-
- @Binds
- @IntoMap
- @ClassKey(TouchpadTutorialActivity::class)
- fun activity(impl: TouchpadTutorialActivity): Activity
-}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt
new file mode 100644
index 0000000..238e8a1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/TouchpadTutorialModule.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 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.systemui.touchpad.tutorial
+
+import android.app.Activity
+import androidx.compose.runtime.Composable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.inputdevice.tutorial.TouchpadTutorialScreensProvider
+import com.android.systemui.model.SysUiState
+import com.android.systemui.settings.DisplayTracker
+import com.android.systemui.touchpad.tutorial.domain.interactor.TouchpadGesturesInteractor
+import com.android.systemui.touchpad.tutorial.ui.composable.BackGestureTutorialScreen
+import com.android.systemui.touchpad.tutorial.ui.composable.HomeGestureTutorialScreen
+import com.android.systemui.touchpad.tutorial.ui.view.TouchpadTutorialActivity
+import dagger.Binds
+import dagger.Module
+import dagger.Provides
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import kotlinx.coroutines.CoroutineScope
+
+@Module
+interface TouchpadTutorialModule {
+
+ @Binds
+ @IntoMap
+ @ClassKey(TouchpadTutorialActivity::class)
+ fun activity(impl: TouchpadTutorialActivity): Activity
+
+ companion object {
+ @Provides
+ fun touchpadScreensProvider(): TouchpadTutorialScreensProvider {
+ return ScreensProvider
+ }
+
+ @SysUISingleton
+ @Provides
+ fun touchpadGesturesInteractor(
+ sysUiState: SysUiState,
+ displayTracker: DisplayTracker,
+ @Background backgroundScope: CoroutineScope
+ ): TouchpadGesturesInteractor {
+ return TouchpadGesturesInteractor(sysUiState, displayTracker, backgroundScope)
+ }
+ }
+}
+
+private object ScreensProvider : TouchpadTutorialScreensProvider {
+ @Composable
+ override fun BackGesture(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) {
+ BackGestureTutorialScreen(onDoneButtonClicked, onBack)
+ }
+
+ @Composable
+ override fun HomeGesture(onDoneButtonClicked: () -> Unit, onBack: () -> Unit) {
+ HomeGestureTutorialScreen(onDoneButtonClicked, onBack)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/domain/interactor/TouchpadGesturesInteractor.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/domain/interactor/TouchpadGesturesInteractor.kt
index b6c2ae7..df95232 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/domain/interactor/TouchpadGesturesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/domain/interactor/TouchpadGesturesInteractor.kt
@@ -16,22 +16,16 @@
package com.android.systemui.touchpad.tutorial.domain.interactor
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.model.SysUiState
import com.android.systemui.settings.DisplayTracker
import com.android.systemui.shared.system.QuickStepContract
-import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
-@SysUISingleton
-class TouchpadGesturesInteractor
-@Inject
-constructor(
+class TouchpadGesturesInteractor(
private val sysUiState: SysUiState,
private val displayTracker: DisplayTracker,
- @Background private val backgroundScope: CoroutineScope
+ private val backgroundScope: CoroutineScope
) {
fun disableGestures() {
setGesturesState(disabled = true)
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
index 5980e1d..1c8041f 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/BackGestureTutorialScreen.kt
@@ -21,6 +21,8 @@
import androidx.compose.runtime.remember
import com.airbnb.lottie.compose.rememberLottieDynamicProperties
import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig
+import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty
import com.android.systemui.res.R
import com.android.systemui.touchpad.tutorial.ui.gesture.BackGestureMonitor
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
index dfe9c0d..57d7c84 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/GestureTutorialScreen.kt
@@ -28,6 +28,9 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.platform.LocalContext
+import com.android.systemui.inputdevice.tutorial.ui.composable.ActionTutorialContent
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.FINISHED
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.IN_PROGRESS
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
index ed3110c..0a6283a 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/HomeGestureTutorialScreen.kt
@@ -21,6 +21,8 @@
import androidx.compose.runtime.remember
import com.airbnb.lottie.compose.rememberLottieDynamicProperties
import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialScreenConfig
+import com.android.systemui.inputdevice.tutorial.ui.composable.rememberColorFilterProperty
import com.android.systemui.res.R
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
import com.android.systemui.touchpad.tutorial.ui.gesture.HomeGestureMonitor
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
index 14355fa..65b452a 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/composable/TutorialSelectionScreen.kt
@@ -34,6 +34,7 @@
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
+import com.android.systemui.inputdevice.tutorial.ui.composable.DoneButton
import com.android.systemui.res.R
@Composable
diff --git a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
index 48e6397..256c5b5 100644
--- a/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/touchpad/tutorial/ui/view/TouchpadTutorialActivity.kt
@@ -27,7 +27,7 @@
import androidx.lifecycle.Lifecycle.State.STARTED
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.theme.PlatformTheme
-import com.android.systemui.touchpad.tutorial.ui.composable.ActionKeyTutorialScreen
+import com.android.systemui.inputdevice.tutorial.ui.composable.ActionKeyTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.BackGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.HomeGestureTutorialScreen
import com.android.systemui.touchpad.tutorial.ui.composable.TutorialSelectionScreen
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
index 5d8b6f1..d39daaf 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
@@ -79,13 +79,15 @@
localBluetoothManager: LocalBluetoothManager?,
@Application coroutineScope: CoroutineScope,
@Background coroutineContext: CoroutineContext,
+ volumeLogger: VolumeLogger
): AudioSharingRepository =
if (Flags.enableLeAudioSharing() && localBluetoothManager != null) {
AudioSharingRepositoryImpl(
contentResolver,
localBluetoothManager,
coroutineScope,
- coroutineContext
+ coroutineContext,
+ volumeLogger
)
} else {
AudioSharingRepositoryEmptyImpl()
diff --git a/packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt b/packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt
index 869a82a..d6b159e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/shared/VolumeLogger.kt
@@ -16,7 +16,8 @@
package com.android.systemui.volume.shared
-import com.android.settingslib.volume.data.repository.AudioRepositoryImpl
+import com.android.settingslib.volume.shared.AudioLogger
+import com.android.settingslib.volume.shared.AudioSharingLogger
import com.android.settingslib.volume.shared.model.AudioStream
import com.android.settingslib.volume.shared.model.AudioStreamModel
import com.android.systemui.dagger.SysUISingleton
@@ -30,7 +31,7 @@
/** Logs general System UI volume events. */
@SysUISingleton
class VolumeLogger @Inject constructor(@VolumeLog private val logBuffer: LogBuffer) :
- AudioRepositoryImpl.Logger {
+ AudioLogger, AudioSharingLogger {
override fun onSetVolumeRequested(audioStream: AudioStream, volume: Int) {
logBuffer.log(
@@ -55,4 +56,35 @@
{ "Volume update received: stream=$str1 volume=$int1" }
)
}
+
+ override fun onAudioSharingStateChanged(state: Boolean) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { bool1 = state },
+ { "Audio sharing state update: state=$bool1" }
+ )
+ }
+
+ override fun onSecondaryGroupIdChanged(groupId: Int) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { int1 = groupId },
+ { "Secondary group id in audio sharing update: groupId=$int1" }
+ )
+ }
+
+ override fun onVolumeMapChanged(map: Map<Int, Int>) {
+ logBuffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = map.toString() },
+ { "Volume map update: map=$str1" }
+ )
+ }
+
+ override fun onSetDeviceVolumeRequested(volume: Int) {
+ logBuffer.log(TAG, LogLevel.DEBUG, { int1 = volume }, { "Set device volume: volume=$int1" })
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 9ca0591..50efc21 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -34,6 +34,8 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
@@ -378,8 +380,8 @@
}
@Override
- public void setImeWindowStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
if (displayId == mDisplayTracker.getDefaultDisplayId()
&& (vis & InputMethodService.IME_VISIBLE) != 0) {
oneHanded.stopOneHanded(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index e3a38a8..37f1a3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -443,7 +443,7 @@
mViewMediator.onSystemReady();
TestableLooper.get(this).processAllMessages();
- mViewMediator.setShowingLocked(false);
+ mViewMediator.setShowingLocked(false, "");
TestableLooper.get(this).processAllMessages();
mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER);
@@ -463,7 +463,7 @@
mViewMediator.onSystemReady();
TestableLooper.get(this).processAllMessages();
- mViewMediator.setShowingLocked(false);
+ mViewMediator.setShowingLocked(false, "");
TestableLooper.get(this).processAllMessages();
mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER);
@@ -570,7 +570,7 @@
// When showing and provisioned
mViewMediator.onSystemReady();
when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
- mViewMediator.setShowingLocked(true);
+ mViewMediator.setShowingLocked(true, "");
// and a SIM becomes locked and requires a PIN
mViewMediator.mUpdateCallback.onSimStateChanged(
@@ -579,7 +579,7 @@
TelephonyManager.SIM_STATE_PIN_REQUIRED);
// and the keyguard goes away
- mViewMediator.setShowingLocked(false);
+ mViewMediator.setShowingLocked(false, "");
when(mKeyguardStateController.isShowing()).thenReturn(false);
mViewMediator.mUpdateCallback.onKeyguardVisibilityChanged(false);
@@ -595,7 +595,7 @@
// When showing and provisioned
mViewMediator.onSystemReady();
when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
- mViewMediator.setShowingLocked(false);
+ mViewMediator.setShowingLocked(false, "");
// and a SIM becomes locked and requires a PIN
mViewMediator.mUpdateCallback.onSimStateChanged(
@@ -604,7 +604,7 @@
TelephonyManager.SIM_STATE_PIN_REQUIRED);
// and the keyguard goes away
- mViewMediator.setShowingLocked(false);
+ mViewMediator.setShowingLocked(false, "");
when(mKeyguardStateController.isShowing()).thenReturn(false);
mViewMediator.mUpdateCallback.onKeyguardVisibilityChanged(false);
@@ -843,7 +843,7 @@
mViewMediator.onSystemReady();
TestableLooper.get(this).processAllMessages();
- mViewMediator.setShowingLocked(false);
+ mViewMediator.setShowingLocked(false, "");
TestableLooper.get(this).processAllMessages();
mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER);
@@ -863,7 +863,7 @@
mViewMediator.onSystemReady();
TestableLooper.get(this).processAllMessages();
- mViewMediator.setShowingLocked(false);
+ mViewMediator.setShowingLocked(false, "");
TestableLooper.get(this).processAllMessages();
mViewMediator.onStartedGoingToSleep(OFF_BECAUSE_OF_USER);
@@ -978,7 +978,7 @@
@Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public void testDoKeyguardWhileInteractive_resets() {
- mViewMediator.setShowingLocked(true);
+ mViewMediator.setShowingLocked(true, "");
when(mKeyguardStateController.isShowing()).thenReturn(true);
TestableLooper.get(this).processAllMessages();
@@ -992,7 +992,7 @@
@Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public void testDoKeyguardWhileNotInteractive_showsInsteadOfResetting() {
- mViewMediator.setShowingLocked(true);
+ mViewMediator.setShowingLocked(true, "");
when(mKeyguardStateController.isShowing()).thenReturn(true);
TestableLooper.get(this).processAllMessages();
@@ -1051,7 +1051,7 @@
mViewMediator.onSystemReady();
processAllMessagesAndBgExecutorMessages();
- mViewMediator.setShowingLocked(true);
+ mViewMediator.setShowingLocked(true, "");
RemoteAnimationTarget[] apps = new RemoteAnimationTarget[]{
mock(RemoteAnimationTarget.class)
@@ -1123,7 +1123,7 @@
@Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public void testNotStartingKeyguardWhenFlagIsDisabled() {
- mViewMediator.setShowingLocked(false);
+ mViewMediator.setShowingLocked(false, "");
when(mKeyguardStateController.isShowing()).thenReturn(false);
mViewMediator.onDreamingStarted();
@@ -1133,7 +1133,7 @@
@Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public void testStartingKeyguardWhenFlagIsEnabled() {
- mViewMediator.setShowingLocked(true);
+ mViewMediator.setShowingLocked(true, "");
when(mKeyguardStateController.isShowing()).thenReturn(true);
mViewMediator.onDreamingStarted();
@@ -1174,7 +1174,7 @@
TestableLooper.get(this).processAllMessages();
// WHEN keyguard visibility becomes FALSE
- mViewMediator.setShowingLocked(false);
+ mViewMediator.setShowingLocked(false, "");
keyguardUpdateMonitorCallback.onKeyguardVisibilityChanged(false);
TestableLooper.get(this).processAllMessages();
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 6916bbd..d10ea1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -15,7 +15,9 @@
package com.android.systemui.statusbar;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
+import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING;
import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
+import static android.inputmethodservice.InputMethodService.IME_ACTIVE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
@@ -194,9 +196,11 @@
@Test
public void testShowImeButton() {
- mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, 1, 2, true);
+ mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, IME_ACTIVE,
+ BACK_DISPOSITION_ADJUST_NOTHING, true);
waitForIdleSync();
- verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(1), eq(2), eq(true));
+ verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(IME_ACTIVE),
+ eq(BACK_DISPOSITION_ADJUST_NOTHING), eq(true));
}
@Test
@@ -204,11 +208,13 @@
// First show in default display to update the "last updated ime display"
testShowImeButton();
- mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, 1, 2, true);
+ mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, IME_ACTIVE,
+ BACK_DISPOSITION_ADJUST_NOTHING, true);
waitForIdleSync();
- verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(0),
+ verify(mCallbacks).setImeWindowStatus(eq(DEFAULT_DISPLAY), eq(0) /* vis */,
eq(BACK_DISPOSITION_DEFAULT), eq(false));
- verify(mCallbacks).setImeWindowStatus(eq(SECONDARY_DISPLAY), eq(1), eq(2), eq(true));
+ verify(mCallbacks).setImeWindowStatus(eq(SECONDARY_DISPLAY), eq(IME_ACTIVE),
+ eq(BACK_DISPOSITION_ADJUST_NOTHING), eq(true));
}
@Test
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt
index b6194e3..bbe753e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt
@@ -27,7 +27,9 @@
class FakeQSSceneAdapter(
private val inflateDelegate: suspend (Context) -> View,
override val qqsHeight: Int = 0,
+ override val squishedQqsHeight: Int = 0,
override val qsHeight: Int = 0,
+ override val squishedQsHeight: Int = 0,
) : QSSceneAdapter {
private val _customizerState = MutableStateFlow<CustomizerState>(CustomizerState.Hidden)
diff --git a/services/Android.bp b/services/Android.bp
index ded7379..0006455 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -120,6 +120,7 @@
":services.backup-sources",
":services.companion-sources",
":services.contentcapture-sources",
+ ":services.appfunctions-sources",
":services.contentsuggestions-sources",
":services.contextualsearch-sources",
":services.coverage-sources",
@@ -217,6 +218,7 @@
"services.autofill",
"services.backup",
"services.companion",
+ "services.appfunctions",
"services.contentcapture",
"services.contentsuggestions",
"services.contextualsearch",
diff --git a/services/appfunctions/Android.bp b/services/appfunctions/Android.bp
new file mode 100644
index 0000000..f8ee823
--- /dev/null
+++ b/services/appfunctions/Android.bp
@@ -0,0 +1,25 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+ name: "services.appfunctions-sources",
+ srcs: ["java/**/*.java"],
+ path: "java",
+ visibility: ["//frameworks/base/services"],
+}
+
+java_library_static {
+ name: "services.appfunctions",
+ defaults: ["platform_service_defaults"],
+ srcs: [
+ ":services.appfunctions-sources",
+ "java/**/*.logtags",
+ ],
+ libs: ["services.core"],
+}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java
new file mode 100644
index 0000000..f30e770
--- /dev/null
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerService.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appfunctions;
+
+import static android.app.appfunctions.flags.Flags.enableAppFunctionManager;
+
+import android.app.appfunctions.IAppFunctionManager;
+import android.content.Context;
+
+import com.android.server.SystemService;
+
+/**
+ * Service that manages app functions.
+ */
+public class AppFunctionManagerService extends SystemService {
+
+ public AppFunctionManagerService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ if (enableAppFunctionManager()) {
+ publishBinderService(Context.APP_FUNCTION_SERVICE, new AppFunctionManagerStub());
+ }
+ }
+
+ private static class AppFunctionManagerStub extends IAppFunctionManager.Stub {
+
+ }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 079b724..ec1993a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -18,6 +18,7 @@
import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED;
import static android.content.Context.DEVICE_ID_DEFAULT;
+import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.INVALID_DISPLAY;
@@ -32,6 +33,8 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManagerInternal;
import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
@@ -99,24 +102,16 @@
/**
* A set of status bits regarding the active IME.
*
- * <p>This value is a combination of following two bits:</p>
- * <dl>
- * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
- * <dd>
- * If this bit is ON, connected IME is ready to accept touch/key events.
- * </dd>
- * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
- * <dd>
- * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
- * </dd>
- * </dl>
- * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
- * {@link InputMethodBindingController#unbindCurrentMethod()}.</em>
+ * <em>Do not update this value outside of {@link #setImeWindowVis} and
+ * {@link InputMethodBindingController#unbindCurrentMethod}.</em>
*/
- @GuardedBy("ImfLock.class") private int mImeWindowVis;
-
+ @ImeWindowVisibility
@GuardedBy("ImfLock.class")
- private int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
+ private int mImeWindowVis;
+
+ @BackDispositionMode
+ @GuardedBy("ImfLock.class")
+ private int mBackDisposition = BACK_DISPOSITION_DEFAULT;
@Nullable private CountDownLatch mLatchForTesting;
@@ -718,22 +713,24 @@
}
@GuardedBy("ImfLock.class")
- void setImeWindowVis(int imeWindowVis) {
+ void setImeWindowVis(@ImeWindowVisibility int imeWindowVis) {
mImeWindowVis = imeWindowVis;
}
+ @ImeWindowVisibility
@GuardedBy("ImfLock.class")
int getImeWindowVis() {
return mImeWindowVis;
}
+ @BackDispositionMode
@GuardedBy("ImfLock.class")
int getBackDisposition() {
return mBackDisposition;
}
@GuardedBy("ImfLock.class")
- void setBackDisposition(int backDisposition) {
+ void setBackDisposition(@BackDispositionMode int backDisposition) {
mBackDisposition = backDisposition;
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 8afbd56..3654283 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -86,6 +86,8 @@
import android.content.res.Resources;
import android.hardware.input.InputManager;
import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.media.AudioManagerInternal;
import android.net.Uri;
import android.os.Binder;
@@ -2618,7 +2620,8 @@
}
@GuardedBy("ImfLock.class")
- private boolean shouldShowImeSwitcherLocked(int visibility, @UserIdInt int userId) {
+ private boolean shouldShowImeSwitcherLocked(@ImeWindowVisibility int visibility,
+ @UserIdInt int userId) {
if (!mShowOngoingImeSwitcherForPhones) return false;
// When the IME switcher dialog is shown, the IME switcher button should be hidden.
// TODO(b/305849394): Make mMenuController multi-user aware.
@@ -2722,8 +2725,8 @@
@BinderThread
@GuardedBy("ImfLock.class")
@SuppressWarnings("deprecation")
- private void setImeWindowStatusLocked(int vis, int backDisposition,
- @NonNull UserData userData) {
+ private void setImeWindowStatusLocked(@ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, @NonNull UserData userData) {
final int topFocusedDisplayId = mWindowManagerInternal.getTopFocusedDisplayId();
final int userId = userData.mUserId;
@@ -2772,7 +2775,7 @@
final int userId = resolveImeUserIdFromDisplayIdLocked(displayId);
if (disableImeIcon) {
final var bindingController = getInputMethodBindingController(userId);
- updateSystemUiLocked(0, bindingController.getBackDisposition(), userId);
+ updateSystemUiLocked(0 /* vis */, bindingController.getBackDisposition(), userId);
} else {
updateSystemUiLocked(userId);
}
@@ -2787,7 +2790,8 @@
}
@GuardedBy("ImfLock.class")
- private void updateSystemUiLocked(int vis, int backDisposition, @UserIdInt int userId) {
+ private void updateSystemUiLocked(@ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, @UserIdInt int userId) {
// To minimize app compat risk, ignore background users' request for single-user mode.
// TODO(b/357178609): generalize the logic and remove this special rule.
if (!mConcurrentMultiUserModeEnabled && userId != mCurrentImeUserId) {
@@ -6812,7 +6816,8 @@
@BinderThread
@Override
- public void setImeWindowStatusAsync(int vis, int backDisposition) {
+ public void setImeWindowStatusAsync(@ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition) {
synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(mToken, mUserData)) {
return;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
index c77b768..202543c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -614,242 +614,61 @@
}
}
- @VisibleForTesting
- public static class ControllerImpl {
-
- @NonNull
- private final DynamicRotationList mSwitchingAwareRotationList;
- @NonNull
- private final StaticRotationList mSwitchingUnawareRotationList;
- /** List of input methods and subtypes. */
- @Nullable
- private final RotationList mRotationList;
- /** List of input methods and subtypes suitable for hardware keyboards. */
- @Nullable
- private final RotationList mHardwareRotationList;
-
- /**
- * Whether there was a user action since the last input method and subtype switch.
- * Used to determine the switching behaviour for {@link #MODE_AUTO}.
- */
- private boolean mUserActionSinceSwitch;
-
- @NonNull
- public static ControllerImpl createFrom(@Nullable ControllerImpl currentInstance,
- @NonNull List<ImeSubtypeListItem> sortedEnabledItems,
- @NonNull List<ImeSubtypeListItem> hardwareKeyboardItems) {
- final var switchingAwareImeSubtypes = filterImeSubtypeList(sortedEnabledItems,
- true /* supportsSwitchingToNextInputMethod */);
- final var switchingUnawareImeSubtypes = filterImeSubtypeList(sortedEnabledItems,
- false /* supportsSwitchingToNextInputMethod */);
-
- final DynamicRotationList switchingAwareRotationList;
- if (currentInstance != null && Objects.equals(
- currentInstance.mSwitchingAwareRotationList.mImeSubtypeList,
- switchingAwareImeSubtypes)) {
- // Can reuse the current instance.
- switchingAwareRotationList = currentInstance.mSwitchingAwareRotationList;
- } else {
- switchingAwareRotationList = new DynamicRotationList(switchingAwareImeSubtypes);
- }
-
- final StaticRotationList switchingUnawareRotationList;
- if (currentInstance != null && Objects.equals(
- currentInstance.mSwitchingUnawareRotationList.mImeSubtypeList,
- switchingUnawareImeSubtypes)) {
- // Can reuse the current instance.
- switchingUnawareRotationList = currentInstance.mSwitchingUnawareRotationList;
- } else {
- switchingUnawareRotationList = new StaticRotationList(switchingUnawareImeSubtypes);
- }
-
- final RotationList rotationList;
- if (!Flags.imeSwitcherRevamp()) {
- rotationList = null;
- } else if (currentInstance != null && currentInstance.mRotationList != null
- && Objects.equals(
- currentInstance.mRotationList.mItems, sortedEnabledItems)) {
- // Can reuse the current instance.
- rotationList = currentInstance.mRotationList;
- } else {
- rotationList = new RotationList(sortedEnabledItems);
- }
-
- final RotationList hardwareRotationList;
- if (!Flags.imeSwitcherRevamp()) {
- hardwareRotationList = null;
- } else if (currentInstance != null && currentInstance.mHardwareRotationList != null
- && Objects.equals(
- currentInstance.mHardwareRotationList.mItems, hardwareKeyboardItems)) {
- // Can reuse the current instance.
- hardwareRotationList = currentInstance.mHardwareRotationList;
- } else {
- hardwareRotationList = new RotationList(hardwareKeyboardItems);
- }
-
- return new ControllerImpl(switchingAwareRotationList, switchingUnawareRotationList,
- rotationList, hardwareRotationList);
- }
-
- private ControllerImpl(@NonNull DynamicRotationList switchingAwareRotationList,
- @NonNull StaticRotationList switchingUnawareRotationList,
- @Nullable RotationList rotationList,
- @Nullable RotationList hardwareRotationList) {
- mSwitchingAwareRotationList = switchingAwareRotationList;
- mSwitchingUnawareRotationList = switchingUnawareRotationList;
- mRotationList = rotationList;
- mHardwareRotationList = hardwareRotationList;
- }
-
- @Nullable
- public ImeSubtypeListItem getNextInputMethod(boolean onlyCurrentIme,
- @Nullable InputMethodInfo imi, @Nullable InputMethodSubtype subtype,
- @SwitchMode int mode, boolean forward) {
- if (imi == null) {
- return null;
- }
- if (Flags.imeSwitcherRevamp() && mRotationList != null) {
- return mRotationList.next(imi, subtype, onlyCurrentIme,
- isRecency(mode, forward), forward);
- } else if (imi.supportsSwitchingToNextInputMethod()) {
- return mSwitchingAwareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi,
- subtype);
- } else {
- return mSwitchingUnawareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi,
- subtype);
- }
- }
-
- @Nullable
- public ImeSubtypeListItem getNextInputMethodForHardware(boolean onlyCurrentIme,
- @NonNull InputMethodInfo imi, @Nullable InputMethodSubtype subtype,
- @SwitchMode int mode, boolean forward) {
- if (Flags.imeSwitcherRevamp() && mHardwareRotationList != null) {
- return mHardwareRotationList.next(imi, subtype, onlyCurrentIme,
- isRecency(mode, forward), forward);
- }
- return null;
- }
-
- /**
- * Called when the user took an action that should update the recency of the current
- * input method and subtype in the switching list.
- *
- * @param imi the currently selected input method.
- * @param subtype the currently selected input method subtype, if any.
- * @return {@code true} if the recency was updated, otherwise {@code false}.
- * @see android.inputmethodservice.InputMethodServiceInternal#notifyUserActionIfNecessary()
- */
- public boolean onUserActionLocked(@NonNull InputMethodInfo imi,
- @Nullable InputMethodSubtype subtype) {
- boolean recencyUpdated = false;
- if (Flags.imeSwitcherRevamp()) {
- if (mRotationList != null) {
- recencyUpdated |= mRotationList.setMostRecent(imi, subtype);
- }
- if (mHardwareRotationList != null) {
- recencyUpdated |= mHardwareRotationList.setMostRecent(imi, subtype);
- }
- if (recencyUpdated) {
- mUserActionSinceSwitch = true;
- }
- } else if (imi.supportsSwitchingToNextInputMethod()) {
- mSwitchingAwareRotationList.onUserAction(imi, subtype);
- }
- return recencyUpdated;
- }
-
- /** Called when the input method and subtype was changed. */
- public void onInputMethodSubtypeChanged() {
- mUserActionSinceSwitch = false;
- }
-
- /**
- * Whether the given mode and direction result in recency or static order.
- *
- * <p>{@link #MODE_AUTO} resolves to the recency order for the first forwards switch
- * after an {@link #onUserActionLocked user action}, and otherwise to the static order.</p>
- *
- * @param mode the switching mode.
- * @param forward the switching direction.
- * @return {@code true} for the recency order, otherwise {@code false}.
- */
- private boolean isRecency(@SwitchMode int mode, boolean forward) {
- if (mode == MODE_AUTO && mUserActionSinceSwitch && forward) {
- return true;
- } else {
- return mode == MODE_RECENT;
- }
- }
-
- @NonNull
- private static List<ImeSubtypeListItem> filterImeSubtypeList(
- @NonNull List<ImeSubtypeListItem> items,
- boolean supportsSwitchingToNextInputMethod) {
- final ArrayList<ImeSubtypeListItem> result = new ArrayList<>();
- final int numItems = items.size();
- for (int i = 0; i < numItems; i++) {
- final ImeSubtypeListItem item = items.get(i);
- if (item.mImi.supportsSwitchingToNextInputMethod()
- == supportsSwitchingToNextInputMethod) {
- result.add(item);
- }
- }
- return result;
- }
-
- protected void dump(@NonNull Printer pw, @NonNull String prefix) {
- pw.println(prefix + "mSwitchingAwareRotationList:");
- mSwitchingAwareRotationList.dump(pw, prefix + " ");
- pw.println(prefix + "mSwitchingUnawareRotationList:");
- mSwitchingUnawareRotationList.dump(pw, prefix + " ");
- if (Flags.imeSwitcherRevamp()) {
- if (mRotationList != null) {
- pw.println(prefix + "mRotationList:");
- mRotationList.dump(pw, prefix + " ");
- }
- if (mHardwareRotationList != null) {
- pw.println(prefix + "mHardwareRotationList:");
- mHardwareRotationList.dump(pw, prefix + " ");
- }
- pw.println(prefix + "User action since last switch: " + mUserActionSinceSwitch);
- }
- }
- }
-
@NonNull
- private ControllerImpl mController;
-
- InputMethodSubtypeSwitchingController() {
- mController = ControllerImpl.createFrom(null, Collections.emptyList(),
- Collections.emptyList());
- }
+ private DynamicRotationList mSwitchingAwareRotationList =
+ new DynamicRotationList(Collections.emptyList());
+ @NonNull
+ private StaticRotationList mSwitchingUnawareRotationList =
+ new StaticRotationList(Collections.emptyList());
+ /** List of input methods and subtypes. */
+ @NonNull
+ private RotationList mRotationList = new RotationList(Collections.emptyList());
+ /** List of input methods and subtypes suitable for hardware keyboards. */
+ @NonNull
+ private RotationList mHardwareRotationList = new RotationList(Collections.emptyList());
/**
- * Called when the user took an action that should update the recency of the current
- * input method and subtype in the switching list.
- *
- * @param imi the currently selected input method.
- * @param subtype the currently selected input method subtype, if any.
- * @see android.inputmethodservice.InputMethodServiceInternal#notifyUserActionIfNecessary()
+ * Whether there was a user action since the last input method and subtype switch.
+ * Used to determine the switching behaviour for {@link #MODE_AUTO}.
*/
- public void onUserActionLocked(@NonNull InputMethodInfo imi,
- @Nullable InputMethodSubtype subtype) {
- mController.onUserActionLocked(imi, subtype);
- }
+ private boolean mUserActionSinceSwitch;
- /** Called when the input method and subtype was changed. */
- public void onInputMethodSubtypeChanged() {
- mController.onInputMethodSubtypeChanged();
- }
+ /**
+ * Updates the list of input methods and subtypes used for switching. If the given items are
+ * equal to the existing ones (regardless of recency order), the update is skipped and the
+ * current recency order is kept. Otherwise, the recency order is reset.
+ *
+ * @param sortedEnabledItems the sorted list of enabled input methods and subtypes.
+ * @param hardwareKeyboardItems the unsorted list of enabled input method and subtypes
+ * suitable for hardware keyboards.
+ */
+ @VisibleForTesting
+ void update(@NonNull List<ImeSubtypeListItem> sortedEnabledItems,
+ @NonNull List<ImeSubtypeListItem> hardwareKeyboardItems) {
+ final var switchingAwareImeSubtypes = filterImeSubtypeList(sortedEnabledItems,
+ true /* supportsSwitchingToNextInputMethod */);
+ final var switchingUnawareImeSubtypes = filterImeSubtypeList(sortedEnabledItems,
+ false /* supportsSwitchingToNextInputMethod */);
- public void resetCircularListLocked(@NonNull Context context,
- @NonNull InputMethodSettings settings) {
- mController = ControllerImpl.createFrom(mController,
- getSortedInputMethodAndSubtypeList(
- false /* includeAuxiliarySubtypes */, false /* isScreenLocked */,
- false /* forImeMenu */, context, settings),
- getInputMethodAndSubtypeListForHardwareKeyboard(context, settings));
+ if (!Objects.equals(mSwitchingAwareRotationList.mImeSubtypeList,
+ switchingAwareImeSubtypes)) {
+ mSwitchingAwareRotationList = new DynamicRotationList(switchingAwareImeSubtypes);
+ }
+
+ if (!Objects.equals(mSwitchingUnawareRotationList.mImeSubtypeList,
+ switchingUnawareImeSubtypes)) {
+ mSwitchingUnawareRotationList = new StaticRotationList(switchingUnawareImeSubtypes);
+ }
+
+ if (Flags.imeSwitcherRevamp()
+ && !Objects.equals(mRotationList.mItems, sortedEnabledItems)) {
+ mRotationList = new RotationList(sortedEnabledItems);
+ }
+
+ if (Flags.imeSwitcherRevamp()
+ && !Objects.equals(mHardwareRotationList.mItems, hardwareKeyboardItems)) {
+ mHardwareRotationList = new RotationList(hardwareKeyboardItems);
+ }
}
/**
@@ -869,7 +688,19 @@
public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme,
@Nullable InputMethodInfo imi, @Nullable InputMethodSubtype subtype,
@SwitchMode int mode, boolean forward) {
- return mController.getNextInputMethod(onlyCurrentIme, imi, subtype, mode, forward);
+ if (imi == null) {
+ return null;
+ }
+ if (Flags.imeSwitcherRevamp()) {
+ return mRotationList.next(imi, subtype, onlyCurrentIme,
+ isRecency(mode, forward), forward);
+ } else if (imi.supportsSwitchingToNextInputMethod()) {
+ return mSwitchingAwareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi,
+ subtype);
+ } else {
+ return mSwitchingUnawareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi,
+ subtype);
+ }
}
/**
@@ -890,11 +721,98 @@
public ImeSubtypeListItem getNextInputMethodForHardware(boolean onlyCurrentIme,
@NonNull InputMethodInfo imi, @Nullable InputMethodSubtype subtype,
@SwitchMode int mode, boolean forward) {
- return mController.getNextInputMethodForHardware(onlyCurrentIme, imi, subtype, mode,
- forward);
+ if (Flags.imeSwitcherRevamp()) {
+ return mHardwareRotationList.next(imi, subtype, onlyCurrentIme,
+ isRecency(mode, forward), forward);
+ }
+ return null;
}
- public void dump(@NonNull Printer pw, @NonNull String prefix) {
- mController.dump(pw, prefix);
+ /**
+ * Called when the user took an action that should update the recency of the current
+ * input method and subtype in the switching list.
+ *
+ * @param imi the currently selected input method.
+ * @param subtype the currently selected input method subtype, if any.
+ * @return {@code true} if the recency was updated, otherwise {@code false}.
+ * @see android.inputmethodservice.InputMethodServiceInternal#notifyUserActionIfNecessary()
+ */
+ public boolean onUserActionLocked(@NonNull InputMethodInfo imi,
+ @Nullable InputMethodSubtype subtype) {
+ boolean recencyUpdated = false;
+ if (Flags.imeSwitcherRevamp()) {
+ recencyUpdated |= mRotationList.setMostRecent(imi, subtype);
+ recencyUpdated |= mHardwareRotationList.setMostRecent(imi, subtype);
+ if (recencyUpdated) {
+ mUserActionSinceSwitch = true;
+ }
+ } else if (imi.supportsSwitchingToNextInputMethod()) {
+ mSwitchingAwareRotationList.onUserAction(imi, subtype);
+ }
+ return recencyUpdated;
+ }
+
+ /** Called when the input method and subtype was changed. */
+ public void onInputMethodSubtypeChanged() {
+ mUserActionSinceSwitch = false;
+ }
+
+ /**
+ * Whether the given mode and direction result in recency or static order.
+ *
+ * <p>{@link #MODE_AUTO} resolves to the recency order for the first forwards switch
+ * after an {@link #onUserActionLocked user action}, and otherwise to the static order.</p>
+ *
+ * @param mode the switching mode.
+ * @param forward the switching direction.
+ * @return {@code true} for the recency order, otherwise {@code false}.
+ */
+ private boolean isRecency(@SwitchMode int mode, boolean forward) {
+ if (mode == MODE_AUTO && mUserActionSinceSwitch && forward) {
+ return true;
+ } else {
+ return mode == MODE_RECENT;
+ }
+ }
+
+ @NonNull
+ private static List<ImeSubtypeListItem> filterImeSubtypeList(
+ @NonNull List<ImeSubtypeListItem> items,
+ boolean supportsSwitchingToNextInputMethod) {
+ final ArrayList<ImeSubtypeListItem> result = new ArrayList<>();
+ final int numItems = items.size();
+ for (int i = 0; i < numItems; i++) {
+ final ImeSubtypeListItem item = items.get(i);
+ if (item.mImi.supportsSwitchingToNextInputMethod()
+ == supportsSwitchingToNextInputMethod) {
+ result.add(item);
+ }
+ }
+ return result;
+ }
+
+ void dump(@NonNull Printer pw, @NonNull String prefix) {
+ pw.println(prefix + "mSwitchingAwareRotationList:");
+ mSwitchingAwareRotationList.dump(pw, prefix + " ");
+ pw.println(prefix + "mSwitchingUnawareRotationList:");
+ mSwitchingUnawareRotationList.dump(pw, prefix + " ");
+ if (Flags.imeSwitcherRevamp()) {
+ pw.println(prefix + "mRotationList:");
+ mRotationList.dump(pw, prefix + " ");
+ pw.println(prefix + "mHardwareRotationList:");
+ mHardwareRotationList.dump(pw, prefix + " ");
+ pw.println(prefix + "User action since last switch: " + mUserActionSinceSwitch);
+ }
+ }
+
+ InputMethodSubtypeSwitchingController() {
+ }
+
+ public void resetCircularListLocked(@NonNull Context context,
+ @NonNull InputMethodSettings settings) {
+ update(getSortedInputMethodAndSubtypeList(
+ false /* includeAuxiliarySubtypes */, false /* isScreenLocked */,
+ false /* forImeMenu */, context, settings),
+ getInputMethodAndSubtypeListForHardwareKeyboard(context, settings));
}
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 98e3e24..22b4d5d 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -686,6 +686,9 @@
(installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
final boolean fullApp =
(installFlags & PackageManager.INSTALL_FULL_APP) != 0;
+ final boolean isPackageDeviceAdmin = mPm.isPackageDeviceAdmin(packageName, userId);
+ final boolean isProtectedPackage = mPm.mProtectedPackages != null
+ && mPm.mProtectedPackages.isPackageStateProtected(userId, packageName);
// writer
synchronized (mPm.mLock) {
@@ -694,7 +697,8 @@
if (pkgSetting == null || pkgSetting.getPkg() == null) {
return Pair.create(PackageManager.INSTALL_FAILED_INVALID_URI, intentSender);
}
- if (instantApp && (pkgSetting.isSystem() || pkgSetting.isUpdatedSystemApp())) {
+ if (instantApp && (pkgSetting.isSystem() || pkgSetting.isUpdatedSystemApp()
+ || isPackageDeviceAdmin || isProtectedPackage)) {
return Pair.create(PackageManager.INSTALL_FAILED_INVALID_URI, intentSender);
}
if (!snapshot.canViewInstantApps(callingUid, UserHandle.getUserId(callingUid))) {
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index c40608d..c95d88e 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -163,6 +163,22 @@
},
{
"name": "CtsUpdateOwnershipEnforcementTestCases"
+ },
+ {
+ "name": "CtsPackageInstallerCUJTestCases",
+ "file_patterns": [
+ "core/java/.*Install.*",
+ "services/core/.*Install.*",
+ "services/core/java/com/android/server/pm/.*"
+ ],
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ }
+ ]
}
],
"imports": [
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index b28da55b..1a2a196 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -360,7 +360,13 @@
IWakeLockCallback callback, int newFlags, String newTag, String newPackageName,
int newOwnerUid, int newOwnerPid, WorkSource newWorkSource, String newHistoryTag,
IWakeLockCallback newCallback) {
-
+ // Todo(b/359154665): We do this because the newWorkSource can potentially be updated
+ // before the request is processed on the notifier thread. This would generally happen is
+ // the Worksource's set method is called, which as of this comment happens only in
+ // PowerManager#setWorksource and WifiManager#WifiLock#setWorksource. Both these places
+ // need to be updated and the WorkSource#set should be deprecated to avoid falling into
+ // such traps
+ newWorkSource = (newWorkSource == null) ? null : new WorkSource(newWorkSource);
final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags);
if (workSource != null && newWorkSource != null
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index a4a29a0..2faa68a 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -20,6 +20,8 @@
import android.app.ITransientNotificationCallback;
import android.content.ComponentName;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.os.Bundle;
import android.os.IBinder;
import android.os.UserHandle;
@@ -54,13 +56,12 @@
* Used by InputMethodManagerService to notify the IME status.
*
* @param displayId The display to which the IME is bound to.
- * @param vis Bit flags about the IME visibility.
- * (e.g. {@link android.inputmethodservice.InputMethodService#IME_ACTIVE})
- * @param backDisposition Bit flags about the IME back disposition.
- * (e.g. {@link android.inputmethodservice.InputMethodService#BACK_DISPOSITION_DEFAULT})
+ * @param vis The IME visibility.
+ * @param backDisposition The IME back disposition.
* @param showImeSwitcher {@code true} when the IME switcher button should be shown.
*/
- void setImeWindowStatus(int displayId, int vis, int backDisposition, boolean showImeSwitcher);
+ void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher);
/**
* See {@link android.app.StatusBarManager#setIcon(String, int, int, String)}.
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index c3601b3c..e71f9ea 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -26,6 +26,7 @@
import static android.app.StatusBarManager.NavBarMode;
import static android.app.StatusBarManager.SessionFlags;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.inputmethodservice.InputMethodService.BACK_DISPOSITION_DEFAULT;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewRootImpl.CLIENT_TRANSIENT;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
@@ -60,6 +61,8 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
+import android.inputmethodservice.InputMethodService.BackDispositionMode;
+import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
import android.media.INearbyMediaDevicesProvider;
import android.media.MediaRoute2Info;
import android.net.Uri;
@@ -534,8 +537,8 @@
}
@Override
- public void setImeWindowStatus(int displayId, int vis, int backDisposition,
- boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
+ @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
StatusBarManagerService.this.setImeWindowStatus(displayId, vis, backDisposition,
showImeSwitcher);
}
@@ -1351,8 +1354,8 @@
}
@Override
- public void setImeWindowStatus(int displayId, final int vis, final int backDisposition,
- final boolean showImeSwitcher) {
+ public void setImeWindowStatus(int displayId, @ImeWindowVisibility final int vis,
+ @BackDispositionMode final int backDisposition, final boolean showImeSwitcher) {
enforceStatusBar();
if (SPEW) {
@@ -1418,8 +1421,10 @@
private String mPackageName = "none";
private int mDisabled1 = 0;
private int mDisabled2 = 0;
+ @ImeWindowVisibility
private int mImeWindowVis = 0;
- private int mImeBackDisposition = 0;
+ @BackDispositionMode
+ private int mImeBackDisposition = BACK_DISPOSITION_DEFAULT;
private boolean mShowImeSwitcher = false;
private LetterboxDetails[] mLetterboxDetails = new LetterboxDetails[0];
@@ -1462,7 +1467,8 @@
return mDisabled1 == disabled1 && mDisabled2 == disabled2;
}
- private void setImeWindowState(final int vis, final int backDisposition,
+ private void setImeWindowState(@ImeWindowVisibility final int vis,
+ @BackDispositionMode final int backDisposition,
final boolean showImeSwitcher) {
mImeWindowVis = vis;
mImeBackDisposition = backDisposition;
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 561ff7d..7212d37 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -407,8 +407,7 @@
change.setTaskFragmentToken(lastParentTfToken);
}
// Only pass the activity token to the client if it belongs to the same process.
- if (Flags.fixPipRestoreToOverlay() && nextFillTaskActivity != null
- && nextFillTaskActivity.getPid() == mOrganizerPid) {
+ if (nextFillTaskActivity != null && nextFillTaskActivity.getPid() == mOrganizerPid) {
change.setOtherActivityToken(nextFillTaskActivity.token);
}
return change;
diff --git a/services/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index 34b9913..2c58c61 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -97,10 +97,10 @@
/**
* @return If a window animation has outsets applied to it.
- * @see Animation#hasExtension()
+ * @see Animation#getExtensionEdges()
*/
public boolean hasExtension() {
- return mAnimation.hasExtension();
+ return mAnimation.getExtensionEdges() != 0;
}
@Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 622c36c..09c54cb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.app.appfunctions.flags.Flags.enableAppFunctionManager;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
@@ -120,6 +121,7 @@
import com.android.server.ambientcontext.AmbientContextManagerService;
import com.android.server.app.GameManagerService;
import com.android.server.appbinding.AppBindingService;
+import com.android.server.appfunctions.AppFunctionManagerService;
import com.android.server.apphibernation.AppHibernationService;
import com.android.server.appop.AppOpMigrationHelper;
import com.android.server.appop.AppOpMigrationHelperImpl;
@@ -1727,6 +1729,12 @@
mSystemServiceManager.startService(LogcatManagerService.class);
t.traceEnd();
+ t.traceBegin("StartAppFunctionManager");
+ if (enableAppFunctionManager()) {
+ mSystemServiceManager.startService(AppFunctionManagerService.class);
+ }
+ t.traceEnd();
+
} catch (Throwable e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service");
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
index a27ad9a..770451c 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -44,7 +44,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ControllerImpl;
import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
import org.junit.Rule;
@@ -178,19 +177,20 @@
return items;
}
- private void assertNextInputMethod(@NonNull ControllerImpl controller, boolean onlyCurrentIme,
- @NonNull ImeSubtypeListItem currentItem, @Nullable ImeSubtypeListItem nextItem) {
+ private void assertNextInputMethod(@NonNull InputMethodSubtypeSwitchingController controller,
+ boolean onlyCurrentIme, @NonNull ImeSubtypeListItem currentItem,
+ @Nullable ImeSubtypeListItem nextItem) {
InputMethodSubtype subtype = null;
if (currentItem.mSubtypeName != null) {
subtype = createTestSubtype(currentItem.mSubtypeName.toString());
}
- final ImeSubtypeListItem nextIme = controller.getNextInputMethod(onlyCurrentIme,
+ final ImeSubtypeListItem nextIme = controller.getNextInputMethodLocked(onlyCurrentIme,
currentItem.mImi, subtype, MODE_STATIC, true /* forward */);
assertEquals(nextItem, nextIme);
}
- private void assertRotationOrder(@NonNull ControllerImpl controller, boolean onlyCurrentIme,
- ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) {
+ private void assertRotationOrder(@NonNull InputMethodSubtypeSwitchingController controller,
+ boolean onlyCurrentIme, ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) {
final int numItems = expectedRotationOrderOfImeSubtypeList.length;
for (int i = 0; i < numItems; i++) {
final int nextIndex = (i + 1) % numItems;
@@ -200,7 +200,7 @@
}
}
- private boolean onUserAction(@NonNull ControllerImpl controller,
+ private boolean onUserAction(@NonNull InputMethodSubtypeSwitchingController controller,
@NonNull ImeSubtypeListItem subtypeListItem) {
InputMethodSubtype subtype = null;
if (subtypeListItem.mSubtypeName != null) {
@@ -228,8 +228,8 @@
final ImeSubtypeListItem japaneseIme_ja_jp = enabledItems.get(6);
final ImeSubtypeListItem switchUnawareJapaneseIme_ja_jp = enabledItems.get(7);
- final ControllerImpl controller = ControllerImpl.createFrom(
- null /* currentInstance */, enabledItems, new ArrayList<>());
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(enabledItems, new ArrayList<>());
// switching-aware loop
assertRotationOrder(controller, false /* onlyCurrentIme */,
@@ -286,8 +286,8 @@
final ImeSubtypeListItem japaneseIme_ja_jp = enabledItems.get(6);
final ImeSubtypeListItem switchUnawareJapaneseIme_ja_jp = enabledItems.get(7);
- final ControllerImpl controller = ControllerImpl.createFrom(
- null /* currentInstance */, enabledItems, new ArrayList<>());
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(enabledItems, new ArrayList<>());
// === switching-aware loop ===
assertRotationOrder(controller, false /* onlyCurrentIme */,
@@ -336,11 +336,10 @@
// Rotation order should be preserved when created with the same subtype list.
final List<ImeSubtypeListItem> sameEnabledItems = createEnabledImeSubtypes();
- final ControllerImpl newController = ControllerImpl.createFrom(controller,
- sameEnabledItems, new ArrayList<>());
- assertRotationOrder(newController, false /* onlyCurrentIme */,
+ controller.update(sameEnabledItems, new ArrayList<>());
+ assertRotationOrder(controller, false /* onlyCurrentIme */,
subtypeAwareIme, latinIme_fr, latinIme_en_us, japaneseIme_ja_jp);
- assertRotationOrder(newController, false /* onlyCurrentIme */,
+ assertRotationOrder(controller, false /* onlyCurrentIme */,
switchingUnawareLatinIme_en_uk, switchingUnawareLatinIme_hi, subtypeUnawareIme,
switchUnawareJapaneseIme_ja_jp);
@@ -348,11 +347,10 @@
final List<ImeSubtypeListItem> differentEnabledItems = List.of(
latinIme_en_us, latinIme_fr, subtypeAwareIme, switchingUnawareLatinIme_en_uk,
switchUnawareJapaneseIme_ja_jp, subtypeUnawareIme);
- final ControllerImpl anotherController = ControllerImpl.createFrom(controller,
- differentEnabledItems, new ArrayList<>());
- assertRotationOrder(anotherController, false /* onlyCurrentIme */,
+ controller.update(differentEnabledItems, new ArrayList<>());
+ assertRotationOrder(controller, false /* onlyCurrentIme */,
latinIme_en_us, latinIme_fr, subtypeAwareIme);
- assertRotationOrder(anotherController, false /* onlyCurrentIme */,
+ assertRotationOrder(controller, false /* onlyCurrentIme */,
switchingUnawareLatinIme_en_uk, switchUnawareJapaneseIme_ja_jp, subtypeUnawareIme);
}
@@ -520,8 +518,8 @@
final var hardwareLatinIme = List.of(hardwareEnglish, hardwareFrench, hardwareItalian);
final var hardwareSimpleIme = List.of(hardwareSimple);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
- hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
final int mode = MODE_STATIC;
@@ -583,8 +581,8 @@
final var hardwareLatinIme = List.of(hardwareEnglish, hardwareFrench, hardwareItalian);
final var hardwareSimpleIme = List.of(hardwareSimple);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
- hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
final int mode = MODE_RECENT;
@@ -666,8 +664,8 @@
final var hardwareLatinIme = List.of(hardwareEnglish, hardwareFrench, hardwareItalian);
final var hardwareSimpleIme = List.of(hardwareSimple);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
- hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
final int mode = MODE_AUTO;
@@ -777,92 +775,73 @@
final var hardwareLatinIme = List.of(hardwareEnglish, hardwareFrench, hardwareItalian);
final var hardwareSimpleIme = List.of(hardwareSimple);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
- hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
final int mode = MODE_RECENT;
// Recency order is initialized to static order.
assertNextOrder(controller, false /* forHardware */, mode,
items, List.of(latinIme, simpleIme));
-
assertNextOrder(controller, true /* forHardware */, mode,
hardwareItems, List.of(hardwareLatinIme, hardwareSimpleIme));
// User action on french IME.
assertTrue("Recency updated for french IME", onUserAction(controller, french));
- final var equalItems = new ArrayList<>(items);
- final var otherItems = new ArrayList<>(items);
- otherItems.remove(simple);
-
- final var equalController = ControllerImpl.createFrom(controller, equalItems,
- hardwareItems);
- final var otherController = ControllerImpl.createFrom(controller, otherItems,
- hardwareItems);
-
final var recencyItems = List.of(french, english, italian, simple);
final var recencyLatinIme = List.of(french, english, italian);
final var recencySimpleIme = List.of(simple);
+ final var equalItems = new ArrayList<>(items);
+ controller.update(equalItems, hardwareItems);
+
+ // The order of non-hardware items remains unchanged when updated with equal items.
assertNextOrder(controller, false /* forHardware */, mode,
recencyItems, List.of(recencyLatinIme, recencySimpleIme));
-
- // The order of equal non-hardware items is unchanged.
- assertNextOrder(equalController, false /* forHardware */, mode,
- recencyItems, List.of(recencyLatinIme, recencySimpleIme));
-
- // The order of other hardware items is reset.
- assertNextOrder(otherController, false /* forHardware */, mode,
- latinIme, List.of(latinIme));
-
- // The order of hardware remains unchanged.
+ // The order of hardware items remains unchanged when only non-hardware items are updated.
assertNextOrder(controller, true /* forHardware */, mode,
hardwareItems, List.of(hardwareLatinIme, hardwareSimpleIme));
- assertNextOrder(equalController, true /* forHardware */, mode,
- hardwareItems, List.of(hardwareLatinIme, hardwareSimpleIme));
+ final var otherItems = new ArrayList<>(items);
+ otherItems.remove(simple);
+ controller.update(otherItems, hardwareItems);
- assertNextOrder(otherController, true /* forHardware */, mode,
+ // The order of non-hardware items is reset when updated with other items.
+ assertNextOrder(controller, false /* forHardware */, mode,
+ latinIme, List.of(latinIme));
+ // The order of hardware items remains unchanged when only non-hardware items are updated.
+ assertNextOrder(controller, true /* forHardware */, mode,
hardwareItems, List.of(hardwareLatinIme, hardwareSimpleIme));
assertTrue("Recency updated for french hardware IME",
onUserAction(controller, hardwareFrench));
- final var equalHardwareItems = new ArrayList<>(hardwareItems);
- final var otherHardwareItems = new ArrayList<>(hardwareItems);
- otherHardwareItems.remove(hardwareSimple);
-
- final var equalHardwareController = ControllerImpl.createFrom(controller, items,
- equalHardwareItems);
- final var otherHardwareController = ControllerImpl.createFrom(controller, items,
- otherHardwareItems);
-
final var recencyHardwareItems =
List.of(hardwareFrench, hardwareEnglish, hardwareItalian, hardwareSimple);
final var recencyHardwareLatinIme =
List.of(hardwareFrench, hardwareEnglish, hardwareItalian);
final var recencyHardwareSimpleIme = List.of(hardwareSimple);
- // The order of non-hardware items remains unchanged.
+ final var equalHardwareItems = new ArrayList<>(hardwareItems);
+ controller.update(otherItems, equalHardwareItems);
+
+ // The order of non-hardware items remains unchanged when only hardware items are updated.
assertNextOrder(controller, false /* forHardware */, mode,
- recencyItems, List.of(recencyLatinIme, recencySimpleIme));
-
- assertNextOrder(equalHardwareController, false /* forHardware */, mode,
- recencyItems, List.of(recencyLatinIme, recencySimpleIme));
-
- assertNextOrder(otherHardwareController, false /* forHardware */, mode,
- recencyItems, List.of(recencyLatinIme, recencySimpleIme));
-
+ latinIme, List.of(latinIme));
+ // The order of hardware items remains unchanged when updated with equal items.
assertNextOrder(controller, true /* forHardware */, mode,
recencyHardwareItems, List.of(recencyHardwareLatinIme, recencyHardwareSimpleIme));
- // The order of equal hardware items is unchanged.
- assertNextOrder(equalHardwareController, true /* forHardware */, mode,
- recencyHardwareItems, List.of(recencyHardwareLatinIme, recencyHardwareSimpleIme));
+ final var otherHardwareItems = new ArrayList<>(hardwareItems);
+ otherHardwareItems.remove(hardwareSimple);
+ controller.update(otherItems, otherHardwareItems);
- // The order of other hardware items is reset.
- assertNextOrder(otherHardwareController, true /* forHardware */, mode,
+ // The order of non-hardware items remains unchanged when only hardware items are updated.
+ assertNextOrder(controller, false /* forHardware */, mode,
+ latinIme, List.of(latinIme));
+ // The order of hardware items is reset when updated with other items.
+ assertNextOrder(controller, true /* forHardware */, mode,
hardwareLatinIme, List.of(hardwareLatinIme));
}
@@ -882,8 +861,8 @@
addTestImeSubtypeListItems(hardwareItems, "hardwareSwitchUnaware", "hardwareSwitchUnaware",
null, false /* supportsSwitchingToNextInputMethod*/);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
- hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
for (int mode = MODE_STATIC; mode <= MODE_AUTO; mode++) {
assertNextOrder(controller, false /* forHardware */, false /* onlyCurrentIme */,
@@ -910,8 +889,7 @@
addTestImeSubtypeListItems(hardwareItems, "HardwareIme", "HardwareIme",
List.of("en", "fr"), true /* supportsSwitchingToNextInputMethod */);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, List.of(),
- List.of());
+ final var controller = new InputMethodSubtypeSwitchingController();
assertNextItemNoAction(controller, false /* forHardware */, items,
null /* expectedNext */);
@@ -940,8 +918,8 @@
addTestImeSubtypeListItems(unknownHardwareItems, "HardwareUnknownIme", "HardwareUnknownIme",
List.of("en", "fr", "it"), true /* supportsSwitchingToNextInputMethod */);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */,
- items, hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
assertNextItemNoAction(controller, false /* forHardware */, items,
null /* expectedNext */);
@@ -979,8 +957,8 @@
addTestImeSubtypeListItems(unknownHardwareItems, "HardwareUnknownIme", "HardwareUnknownIme",
List.of("en", "fr", "it"), true /* supportsSwitchingToNextInputMethod */);
- final var controller = ControllerImpl.createFrom(null /* currentInstance */, items,
- hardwareItems);
+ final var controller = new InputMethodSubtypeSwitchingController();
+ controller.update(items, hardwareItems);
assertTrue("Recency updated for french IME", onUserAction(controller, french));
@@ -1118,8 +1096,9 @@
* @param allItems the list of items across all IMEs.
* @param perImeItems the list of lists of items per IME.
*/
- private static void assertNextOrder(@NonNull ControllerImpl controller, boolean forHardware,
- @SwitchMode int mode, boolean forward, @NonNull List<ImeSubtypeListItem> allItems,
+ private static void assertNextOrder(@NonNull InputMethodSubtypeSwitchingController controller,
+ boolean forHardware, @SwitchMode int mode, boolean forward,
+ @NonNull List<ImeSubtypeListItem> allItems,
@NonNull List<List<ImeSubtypeListItem>> perImeItems) {
assertNextOrder(controller, forHardware, false /* onlyCurrentIme */, mode,
forward, allItems);
@@ -1142,8 +1121,8 @@
* @param allItems the list of items across all IMEs.
* @param perImeItems the list of lists of items per IME.
*/
- private static void assertNextOrder(@NonNull ControllerImpl controller, boolean forHardware,
- @SwitchMode int mode, @NonNull List<ImeSubtypeListItem> allItems,
+ private static void assertNextOrder(@NonNull InputMethodSubtypeSwitchingController controller,
+ boolean forHardware, @SwitchMode int mode, @NonNull List<ImeSubtypeListItem> allItems,
@NonNull List<List<ImeSubtypeListItem>> perImeItems) {
assertNextOrder(controller, forHardware, false /* onlyCurrentIme */, mode,
true /* forward */, allItems);
@@ -1170,7 +1149,7 @@
* @param forward whether to search forwards or backwards in the list.
* @param items the list of items to verify, in the expected order.
*/
- private static void assertNextOrder(@NonNull ControllerImpl controller,
+ private static void assertNextOrder(@NonNull InputMethodSubtypeSwitchingController controller,
boolean forHardware, boolean onlyCurrentIme, @SwitchMode int mode, boolean forward,
@NonNull List<ImeSubtypeListItem> items) {
final int numItems = items.size();
@@ -1214,7 +1193,7 @@
* @param item the item to find the next value from.
* @param expectedNext the expected next value.
*/
- private static void assertNextItem(@NonNull ControllerImpl controller,
+ private static void assertNextItem(@NonNull InputMethodSubtypeSwitchingController controller,
boolean forHardware, boolean onlyCurrentIme, @SwitchMode int mode, boolean forward,
@NonNull ImeSubtypeListItem item, @Nullable ImeSubtypeListItem expectedNext) {
final var nextItem = getNextItem(controller, forHardware, onlyCurrentIme, mode, forward,
@@ -1234,15 +1213,16 @@
* @return the next item found, otherwise {@code null}.
*/
@Nullable
- private static ImeSubtypeListItem getNextItem(@NonNull ControllerImpl controller,
- boolean forHardware, boolean onlyCurrentIme, @SwitchMode int mode, boolean forward,
+ private static ImeSubtypeListItem getNextItem(
+ @NonNull InputMethodSubtypeSwitchingController controller, boolean forHardware,
+ boolean onlyCurrentIme, @SwitchMode int mode, boolean forward,
@NonNull ImeSubtypeListItem item) {
final var subtype = item.mSubtypeName != null
? createTestSubtype(item.mSubtypeName.toString()) : null;
return forHardware
? controller.getNextInputMethodForHardware(
onlyCurrentIme, item.mImi, subtype, mode, forward)
- : controller.getNextInputMethod(
+ : controller.getNextInputMethodLocked(
onlyCurrentIme, item.mImi, subtype, mode, forward);
}
@@ -1255,8 +1235,9 @@
* @param items the list of items to verify.
* @param expectedNext the expected next item.
*/
- private void assertNextItemNoAction(@NonNull ControllerImpl controller, boolean forHardware,
- @NonNull List<ImeSubtypeListItem> items, @Nullable ImeSubtypeListItem expectedNext) {
+ private void assertNextItemNoAction(@NonNull InputMethodSubtypeSwitchingController controller,
+ boolean forHardware, @NonNull List<ImeSubtypeListItem> items,
+ @Nullable ImeSubtypeListItem expectedNext) {
for (var item : items) {
for (int mode = MODE_STATIC; mode <= MODE_AUTO; mode++) {
assertNextItem(controller, forHardware, false /* onlyCurrentIme */, mode,
diff --git a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
index d45e312..fc4d8d8 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/NotifierTest.java
@@ -61,7 +61,6 @@
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.concurrent.Executor;
@@ -264,8 +263,8 @@
BatteryStats.WAKE_TYPE_PARTIAL, false);
verifyNoMoreInteractions(mWakeLockLog, mBatteryStats);
- WorkSource worksourceOld = Mockito.mock(WorkSource.class);
- WorkSource worksourceNew = Mockito.mock(WorkSource.class);
+ WorkSource worksourceOld = new WorkSource(/*uid=*/ 1);
+ WorkSource worksourceNew = new WorkSource(/*uid=*/ 2);
mNotifier.onWakeLockChanging(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
"my.package.name", uid, pid, worksourceOld, /* historyTag= */ null,
@@ -309,6 +308,40 @@
verify(mWakeLockLog).onWakeLockReleased("wakelockTag", uid, -1);
}
+ @Test
+ public void
+ test_notifierProcessesWorkSourceDeepCopy_OnWakelockChanging() throws RemoteException {
+ when(mPowerManagerFlags.improveWakelockLatency()).thenReturn(true);
+ createNotifier();
+ clearInvocations(mWakeLockLog, mBatteryStats, mAppOpsManager);
+ IWakeLockCallback exceptingCallback = new IWakeLockCallback.Stub() {
+ @Override public void onStateChanged(boolean enabled) throws RemoteException {
+ throw new RemoteException("Just testing");
+ }
+ };
+
+ final int uid = 1234;
+ final int pid = 5678;
+ mTestLooper.dispatchAll();
+ WorkSource worksourceOld = new WorkSource(/*uid=*/ 1);
+ WorkSource worksourceNew = new WorkSource(/*uid=*/ 2);
+
+ mNotifier.onWakeLockChanging(PowerManager.PARTIAL_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, worksourceOld, /* historyTag= */ null,
+ exceptingCallback,
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "wakelockTag",
+ "my.package.name", uid, pid, worksourceNew, /* newHistoryTag= */ null,
+ exceptingCallback);
+ // The newWorksource is modified before notifier could process it.
+ worksourceNew.set(/*uid=*/ 3);
+
+ mTestLooper.dispatchAll();
+ verify(mBatteryStats).noteChangeWakelockFromSource(worksourceOld, pid,
+ "wakelockTag", null, BatteryStats.WAKE_TYPE_PARTIAL,
+ new WorkSource(/*uid=*/ 2), pid, "wakelockTag", null,
+ BatteryStats.WAKE_TYPE_FULL, false);
+ }
+
@Test
public void testOnWakeLockListener_FullWakeLock_ProcessesOnHandler() throws RemoteException {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 771e290..e57e36d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -59,6 +59,7 @@
TestWindowContainer(WindowManagerService wm) {
super(wm);
+ setVisibleRequested(true);
}
@Override
diff --git a/tests/FlickerTests/AppLaunch/Android.bp b/tests/FlickerTests/AppLaunch/Android.bp
index 72a9065..b61739f 100644
--- a/tests/FlickerTests/AppLaunch/Android.bp
+++ b/tests/FlickerTests/AppLaunch/Android.bp
@@ -15,6 +15,7 @@
//
package {
+ default_team: "trendy_team_windowing_animations_transitions",
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "frameworks_base_license"
@@ -23,6 +24,9 @@
default_applicable_licenses: ["frameworks_base_license"],
}
+////////////////////////////////////////////////////////////////////////////////
+// Begin to cleanup after CL merges
+
filegroup {
name: "FlickerTestsAppLaunchCommon-src",
srcs: ["src/**/common/*"],
@@ -69,3 +73,122 @@
],
data: ["trace_config/*"],
}
+
+// End to cleanup after CL merges
+////////////////////////////////////////////////////////////////////////////////
+
+android_test {
+ name: "FlickerTestsAppLaunch",
+ defaults: ["FlickerTestsDefault"],
+ manifest: "AndroidManifest.xml",
+ test_config_template: "AndroidTestTemplate.xml",
+ srcs: ["src/**/*"],
+ static_libs: [
+ "FlickerTestsBase",
+ "FlickerTestsAppLaunchCommon",
+ ],
+ data: ["trace_config/*"],
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Begin breakdowns for FlickerTestsAppLaunch module
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-CatchAll",
+ base: "FlickerTestsAppLaunch",
+ exclude_filters: [
+ "com.android.server.wm.flicker.launch.TaskTransitionTest",
+ "com.android.server.wm.flicker.launch.ActivityTransitionTest",
+ "com.android.server.wm.flicker.launch.OpenAppFromIconColdTest",
+ "com.android.server.wm.flicker.launch.OpenAppFromIntentColdAfterCameraTest",
+ "com.android.server.wm.flicker.launch.OpenAppFromIntentColdTest",
+ "com.android.server.wm.flicker.launch.OpenAppFromIntentWarmTest",
+ "com.android.server.wm.flicker.launch.OpenAppFromLockscreenViaIntentTest",
+ "com.android.server.wm.flicker.launch.OpenAppFromOverviewTest",
+ "com.android.server.wm.flicker.launch.OpenCameraFromHomeOnDoubleClickPowerButtonTest",
+ "com.android.server.wm.flicker.launch.OpenTransferSplashscreenAppFromLauncherTransition",
+ "com.android.server.wm.flicker.launch.OverrideTaskTransitionTest",
+ "com.android.server.wm.flicker.launch.TaskTransitionTest",
+ ],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-ActivityTransitionTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.ActivityTransitionTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenAppFromIconColdTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromIconColdTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenAppFromIntentColdAfterCameraTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromIntentColdAfterCameraTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenAppFromIntentColdTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromIntentColdTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenAppFromIntentWarmTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromIntentWarmTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenAppFromLockscreenViaIntentTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromLockscreenViaIntentTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenAppFromOverviewTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenAppFromOverviewTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenCameraFromHomeOnDoubleClickPowerButtonTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenCameraFromHomeOnDoubleClickPowerButtonTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OpenTransferSplashscreenAppFromLauncherTransition",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OpenTransferSplashscreenAppFromLauncherTransition"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-OverrideTaskTransitionTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.OverrideTaskTransitionTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "FlickerTestsAppLaunch-TaskTransitionTest",
+ base: "FlickerTestsAppLaunch",
+ include_filters: ["com.android.server.wm.flicker.launch.TaskTransitionTest"],
+ test_suites: ["device-tests"],
+}
+
+// End breakdowns for FlickerTestsAppLaunch module
+////////////////////////////////////////////////////////////////////////////////