Merge "Cancel Ask-Every-Time support for SMS by default." into main
diff --git a/apex/jobscheduler/service/aconfig/job.aconfig b/apex/jobscheduler/service/aconfig/job.aconfig
index 810be8f..fe95a59 100644
--- a/apex/jobscheduler/service/aconfig/job.aconfig
+++ b/apex/jobscheduler/service/aconfig/job.aconfig
@@ -63,7 +63,7 @@
name: "remove_user_during_user_switch"
namespace: "backstage_power"
description: "Remove started user if user will be stopped due to user switch"
- bug: "321598070"
+ bug: "337077643"
}
flag {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index a593970..ce62ccf 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -550,6 +550,7 @@
field public static final int config_systemTextIntelligence = 17039414; // 0x1040036
field public static final int config_systemUi = 17039418; // 0x104003a
field public static final int config_systemUiIntelligence = 17039410; // 0x1040032
+ field @FlaggedApi("android.permission.flags.system_vendor_intelligence_role_enabled") public static final int config_systemVendorIntelligence;
field public static final int config_systemVisualIntelligence = 17039415; // 0x1040037
field public static final int config_systemWearHealthService = 17039428; // 0x1040044
field public static final int config_systemWellbeing = 17039408; // 0x1040030
@@ -12615,6 +12616,7 @@
field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
field public static final String ACTION_SHOW_RESTRICTED_SETTING_DIALOG = "android.settings.SHOW_RESTRICTED_SETTING_DIALOG";
+ field @FlaggedApi("com.android.internal.telephony.flags.action_sim_preference_settings") public static final String ACTION_SIM_PREFERENCE_SETTINGS = "android.settings.SIM_PREFERENCE_SETTINGS";
field public static final String ACTION_TETHER_PROVISIONING_UI = "android.settings.TETHER_PROVISIONING_UI";
field public static final String ACTION_TETHER_SETTINGS = "android.settings.TETHER_SETTINGS";
field public static final String ACTION_TETHER_UNSUPPORTED_CARRIER_UI = "android.settings.TETHER_UNSUPPORTED_CARRIER_UI";
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 1e971a5..9bb0ba4 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -1294,13 +1294,6 @@
public static record Args(@NonNull String mModule, @Nullable String mApi,
int mMaxEntries, boolean mIsolateUids, boolean mTestMode, boolean mCacheNulls) {
- /**
- * Default values for fields.
- */
- public static final int DEFAULT_MAX_ENTRIES = 32;
- public static final boolean DEFAULT_ISOLATE_UIDS = true;
- public static final boolean DEFAULT_CACHE_NULLS = false;
-
// Validation: the module must be one of the known module strings and the maxEntries must
// be positive.
public Args {
@@ -1315,10 +1308,10 @@
public Args(@NonNull String module) {
this(module,
null, // api
- DEFAULT_MAX_ENTRIES,
- DEFAULT_ISOLATE_UIDS,
+ 32, // maxEntries
+ true, // isolateUids
false, // testMode
- DEFAULT_CACHE_NULLS
+ true // allowNulls
);
}
@@ -1368,7 +1361,7 @@
* Burst a property name into module and api. Throw if the key is invalid. This method is
* used in to transition legacy cache constructors to the args constructor.
*/
- private static Args argsFromProperty(@NonNull String name) {
+ private static Args parseProperty(@NonNull String name) {
throwIfInvalidCacheKey(name);
// Strip off the leading well-known prefix.
String base = name.substring(CACHE_KEY_PREFIX.length() + 1);
@@ -1391,9 +1384,8 @@
*
* @hide
*/
- @Deprecated
public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) {
- this(argsFromProperty(propertyName).maxEntries(maxEntries), propertyName, null);
+ this(parseProperty(propertyName).maxEntries(maxEntries), propertyName, null);
}
/**
@@ -1407,10 +1399,9 @@
* @param cacheName Name of this cache in debug and dumpsys
* @hide
*/
- @Deprecated
public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName,
@NonNull String cacheName) {
- this(argsFromProperty(propertyName).maxEntries(maxEntries), cacheName, null);
+ this(parseProperty(propertyName).maxEntries(maxEntries), cacheName, null);
}
/**
@@ -1866,14 +1857,6 @@
}
/**
- * Invalidate caches in all processes that have the module and api specified in the args.
- * @hide
- */
- public static void invalidateCache(@NonNull Args args) {
- invalidateCache(createPropertyName(args.mModule, args.mApi));
- }
-
- /**
* Invalidate PropertyInvalidatedCache caches in all processes that are keyed on
* {@var name}. This function is synchronous: caches are invalidated upon return.
*
diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java
index a2e9314..8db1567 100644
--- a/core/java/android/os/IpcDataCache.java
+++ b/core/java/android/os/IpcDataCache.java
@@ -400,11 +400,10 @@
}
/**
- * This is a convenience class that encapsulates configuration information for a cache. It
- * may be supplied to the cache constructors in lieu of the other parameters. The class
- * captures maximum entry count, the module, the key, and the api. The key is used to
- * invalidate the cache and may be shared by different caches. The api is a user-visible (in
- * debug) name for the cache.
+ * This is a convenience class that encapsulates configuration information for a
+ * cache. It may be supplied to the cache constructors in lieu of the other
+ * parameters. The class captures maximum entry count, the module, the key, and the
+ * api.
*
* There are three specific use cases supported by this class.
*
@@ -431,8 +430,11 @@
* @hide
*/
public static class Config {
- final Args mArgs;
- final String mName;
+ private final int mMaxEntries;
+ @IpcDataCacheModule
+ private final String mModule;
+ private final String mApi;
+ private final String mName;
/**
* The list of cache names that were created extending this Config. If
@@ -450,20 +452,12 @@
*/
private boolean mDisabled = false;
- /**
- * Fully construct a config.
- */
- private Config(@NonNull Args args, @NonNull String name) {
- mArgs = args;
- mName = name;
- }
-
- /**
- *
- */
public Config(int maxEntries, @NonNull @IpcDataCacheModule String module,
@NonNull String api, @NonNull String name) {
- this(new Args(module).api(api).maxEntries(maxEntries), name);
+ mMaxEntries = maxEntries;
+ mModule = module;
+ mApi = api;
+ mName = name;
}
/**
@@ -479,7 +473,7 @@
* the parameter list.
*/
public Config(@NonNull Config root, @NonNull String api, @NonNull String name) {
- this(root.mArgs.api(api), name);
+ this(root.maxEntries(), root.module(), api, name);
}
/**
@@ -487,7 +481,7 @@
* the parameter list.
*/
public Config(@NonNull Config root, @NonNull String api) {
- this(root.mArgs.api(api), api);
+ this(root.maxEntries(), root.module(), api, api);
}
/**
@@ -496,23 +490,26 @@
* current process.
*/
public Config child(@NonNull String name) {
- final Config result = new Config(mArgs, name);
+ final Config result = new Config(this, api(), name);
registerChild(name);
return result;
}
- /**
- * Set the cacheNull behavior.
- */
- public Config cacheNulls(boolean enable) {
- return new Config(mArgs.cacheNulls(enable), mName);
+ public final int maxEntries() {
+ return mMaxEntries;
}
- /**
- * Set the isolateUidss behavior.
- */
- public Config isolateUids(boolean enable) {
- return new Config(mArgs.isolateUids(enable), mName);
+ @IpcDataCacheModule
+ public final @NonNull String module() {
+ return mModule;
+ }
+
+ public final @NonNull String api() {
+ return mApi;
+ }
+
+ public final @NonNull String name() {
+ return mName;
}
/**
@@ -535,7 +532,7 @@
* Invalidate all caches that share this Config's module and api.
*/
public void invalidateCache() {
- IpcDataCache.invalidateCache(mArgs);
+ IpcDataCache.invalidateCache(mModule, mApi);
}
/**
@@ -567,7 +564,8 @@
* @hide
*/
public IpcDataCache(@NonNull Config config, @NonNull QueryHandler<Query, Result> computer) {
- super(config.mArgs, config.mName, computer);
+ super(new Args(config.module()).maxEntries(config.maxEntries()).api(config.api()),
+ config.name(), computer);
}
/**
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index bfcc5cc..8d35338 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -118,9 +118,10 @@
# Memory
per-file OomKillRecord.java = file:/MEMORY_OWNERS
-# MessageQueue
+# MessageQueue and related classes
per-file MessageQueue.java = mfasheh@google.com, shayba@google.com
per-file Message.java = mfasheh@google.com, shayba@google.com
+per-file TestLooperManager.java = mfasheh@google.com, shayba@google.com
# Stats
per-file IStatsBootstrapAtomService.aidl = file:/services/core/java/com/android/server/stats/OWNERS
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 57e1b58..2c4883f 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -483,3 +483,12 @@
description: "Rate limit async noteOp callbacks for batched noteOperation binder call"
bug: "366013082"
}
+
+flag {
+ name: "system_vendor_intelligence_role_enabled"
+ is_exported: true
+ is_fixed_read_only: true
+ namespace: "permissions"
+ description: "This flag is used to enable the role system_vendor_intelligence"
+ bug: "377553620"
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0ae9ffa..9935be2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2469,6 +2469,25 @@
= "android.settings.APP_NOTIFICATION_BUBBLE_SETTINGS";
/**
+ * Activity Action: Show the settings for users to select their preferred SIM subscription
+ * when a new SIM subscription has become available.
+ * <p>
+ * This Activity will only launch successfully if the newly active subscription ID is set as the
+ * value of {@link EXTRA_SUB_ID} and the value corresponds with an active SIM subscription.
+ * <p>
+ * Input: {@link #EXTRA_SUB_ID}: the subscription ID of the newly active SIM subscription.
+ * <p>
+ * Output: Nothing.
+ *
+ * @hide
+ */
+ @FlaggedApi(com.android.internal.telephony.flags.Flags.FLAG_ACTION_SIM_PREFERENCE_SETTINGS)
+ @SystemApi
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SIM_PREFERENCE_SETTINGS =
+ "android.settings.SIM_PREFERENCE_SETTINGS";
+
+ /**
* Intent Extra: The value of {@link android.app.settings.SettingsEnums#EntryPointType} for
* settings metrics that logs the entry point about physical keyboard settings.
* <p>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1ed81a5..13c125c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -7276,4 +7276,9 @@
<!-- List of protected packages that require biometric authentication for modification
(Disable, force-stop or uninstalling updates). -->
<string-array name="config_biometric_protected_package_names" translatable="false" />
+
+ <!-- Package name of the on-device intelligent processor for vendor specific
+ features. Examples include the search functionality or the app
+ predictor. -->
+ <string name="config_systemVendorIntelligence" translatable="false"></string>
</resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 90f1b8a..7b9d213 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -154,6 +154,9 @@
<!-- @FlaggedApi(android.permission.flags.Flags.FLAG_CROSS_USER_ROLE_PLATFORM_API_ENABLED)
@hide @SystemApi -->
<public name="config_defaultReservedForTestingProfileGroupExclusivity" />
+ <!-- @FlaggedApi(android.permission.flags.Flags.FLAG_SYSTEM_VENDOR_INTELLIGENCE_ROLE_ENABLED)
+ @hide @SystemApi -->
+ <public name="config_systemVendorIntelligence" />
</staging-public-group>
<staging-public-group type="dimen" first-id="0x01b30000">
diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
index bd27337..177c7f0 100644
--- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
+++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
@@ -740,20 +740,5 @@
assertEquals(null, cache.query(30));
// The recompute is 4 because nulls were not cached.
assertEquals(4, cache.getRecomputeCount());
-
- // Verify that the default is not to cache nulls.
- cache = new TestCache(new Args(MODULE_TEST)
- .maxEntries(4).api("testCachingNulls"),
- new TestQuery());
- cache.invalidateCache();
- assertEquals("foo1", cache.query(1));
- assertEquals("foo2", cache.query(2));
- assertEquals(null, cache.query(30));
- assertEquals(3, cache.getRecomputeCount());
- assertEquals("foo1", cache.query(1));
- assertEquals("foo2", cache.query(2));
- assertEquals(null, cache.query(30));
- // The recompute is 4 because nulls were not cached.
- assertEquals(4, cache.getRecomputeCount());
}
}
diff --git a/core/tests/coretests/src/android/os/IpcDataCacheTest.java b/core/tests/coretests/src/android/os/IpcDataCacheTest.java
index 523b1b0..e14608a 100644
--- a/core/tests/coretests/src/android/os/IpcDataCacheTest.java
+++ b/core/tests/coretests/src/android/os/IpcDataCacheTest.java
@@ -16,19 +16,13 @@
package android.os;
-import static android.app.Flags.FLAG_PIC_CACHE_NULLS;
-import static android.app.Flags.FLAG_PIC_ISOLATE_CACHE_BY_UID;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
-import android.app.PropertyInvalidatedCache;
-import android.app.PropertyInvalidatedCache.Args;
import android.multiuser.Flags;
import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.ravenwood.RavenwoodRule;
-import android.os.IpcDataCache;
import androidx.test.filters.SmallTest;
@@ -293,12 +287,7 @@
@Override
public String apply(Integer qv) {
mRecomputeCount += 1;
- // Special case for testing caches of nulls. Integers in the range 30-40 return null.
- if (qv >= 30 && qv < 40) {
- return null;
- } else {
- return "foo" + qv.toString();
- }
+ return "foo" + qv.toString();
}
int getRecomputeCount() {
@@ -417,16 +406,31 @@
}
@Test
- public void testConfigDisable() {
- // Create a set of caches based on a set of chained configs.
+ public void testConfig() {
IpcDataCache.Config a = new IpcDataCache.Config(8, MODULE, "apiA");
TestCache ac = new TestCache(a);
+ assertEquals(8, a.maxEntries());
+ assertEquals(MODULE, a.module());
+ assertEquals("apiA", a.api());
+ assertEquals("apiA", a.name());
IpcDataCache.Config b = new IpcDataCache.Config(a, "apiB");
TestCache bc = new TestCache(b);
+ assertEquals(8, b.maxEntries());
+ assertEquals(MODULE, b.module());
+ assertEquals("apiB", b.api());
+ assertEquals("apiB", b.name());
IpcDataCache.Config c = new IpcDataCache.Config(a, "apiC", "nameC");
TestCache cc = new TestCache(c);
+ assertEquals(8, c.maxEntries());
+ assertEquals(MODULE, c.module());
+ assertEquals("apiC", c.api());
+ assertEquals("nameC", c.name());
IpcDataCache.Config d = a.child("nameD");
TestCache dc = new TestCache(d);
+ assertEquals(8, d.maxEntries());
+ assertEquals(MODULE, d.module());
+ assertEquals("apiA", d.api());
+ assertEquals("nameD", d.name());
a.disableForCurrentProcess();
assertEquals(ac.isDisabled(), true);
@@ -445,7 +449,6 @@
assertEquals(ec.isDisabled(), true);
}
-
// Verify that invalidating the cache from an app process would fail due to lack of permissions.
@Test
@android.platform.test.annotations.DisabledOnRavenwood(
@@ -504,47 +507,4 @@
// Re-enable test mode (so that the cleanup for the test does not throw).
IpcDataCache.setTestMode(true);
}
-
- @RequiresFlagsEnabled(FLAG_PIC_CACHE_NULLS)
- @Test
- public void testCachingNulls() {
- IpcDataCache.Config c =
- new IpcDataCache.Config(4, IpcDataCache.MODULE_TEST, "testCachingNulls");
- TestCache cache;
- cache = new TestCache(c.cacheNulls(true));
- cache.invalidateCache();
- assertEquals("foo1", cache.query(1));
- assertEquals("foo2", cache.query(2));
- assertEquals(null, cache.query(30));
- assertEquals(3, cache.getRecomputeCount());
- assertEquals("foo1", cache.query(1));
- assertEquals("foo2", cache.query(2));
- assertEquals(null, cache.query(30));
- assertEquals(3, cache.getRecomputeCount());
-
- cache = new TestCache(c.cacheNulls(false));
- cache.invalidateCache();
- assertEquals("foo1", cache.query(1));
- assertEquals("foo2", cache.query(2));
- assertEquals(null, cache.query(30));
- assertEquals(3, cache.getRecomputeCount());
- assertEquals("foo1", cache.query(1));
- assertEquals("foo2", cache.query(2));
- assertEquals(null, cache.query(30));
- // The recompute is 4 because nulls were not cached.
- assertEquals(4, cache.getRecomputeCount());
-
- // Verify that the default is not to cache nulls.
- cache = new TestCache(c);
- cache.invalidateCache();
- assertEquals("foo1", cache.query(1));
- assertEquals("foo2", cache.query(2));
- assertEquals(null, cache.query(30));
- assertEquals(3, cache.getRecomputeCount());
- assertEquals("foo1", cache.query(1));
- assertEquals("foo2", cache.query(2));
- assertEquals(null, cache.query(30));
- // The recompute is 4 because nulls were not cached.
- assertEquals(4, cache.getRecomputeCount());
- }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index f46b955..86e0d08 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -152,6 +152,7 @@
import com.android.wm.shell.windowdecor.WindowDecorViewModel;
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer;
import com.android.wm.shell.windowdecor.common.viewhost.DefaultWindowDecorViewHostSupplier;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationPromoController;
import com.android.wm.shell.windowdecor.education.DesktopWindowingEducationTooltipController;
@@ -301,6 +302,7 @@
Transitions transitions,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
FocusTransitionObserver focusTransitionObserver,
+ WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier,
Optional<DesktopModeWindowDecorViewModel> desktopModeWindowDecorViewModel) {
if (desktopModeWindowDecorViewModel.isPresent()) {
return desktopModeWindowDecorViewModel.get();
@@ -318,7 +320,8 @@
rootTaskDisplayAreaOrganizer,
syncQueue,
transitions,
- focusTransitionObserver);
+ focusTransitionObserver,
+ windowDecorViewHostSupplier);
}
@WMSingleton
@@ -343,7 +346,7 @@
@WMSingleton
@Provides
- static WindowDecorViewHostSupplier provideWindowDecorViewHostSupplier(
+ static WindowDecorViewHostSupplier<WindowDecorViewHost> provideWindowDecorViewHostSupplier(
@ShellMainThread @NonNull CoroutineScope mainScope) {
return new DefaultWindowDecorViewHostSupplier(mainScope);
}
@@ -908,6 +911,7 @@
InteractionJankMonitor interactionJankMonitor,
AppToWebGenericLinksParser genericLinksParser,
AssistContentRequester assistContentRequester,
+ WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier,
MultiInstanceHelper multiInstanceHelper,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
AppHandleEducationController appHandleEducationController,
@@ -927,8 +931,8 @@
displayInsetsController, syncQueue, transitions, desktopTasksController,
desktopImmersiveController.get(),
rootTaskDisplayAreaOrganizer, interactionJankMonitor, genericLinksParser,
- assistContentRequester, multiInstanceHelper, desktopTasksLimiter,
- appHandleEducationController, appToWebEducationController,
+ assistContentRequester, windowDecorViewHostSupplier, multiInstanceHelper,
+ desktopTasksLimiter, appHandleEducationController, appToWebEducationController,
windowDecorCaptionHandleRepository, activityOrientationChangeHandler,
focusTransitionObserver, desktopModeEventLogger, desktopModeUiEventLogger));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index e08f9b2..d5a2a40 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -1510,28 +1510,20 @@
/** Open an existing instance of an app. */
fun openInstance(callingTask: RunningTaskInfo, requestedTaskId: Int) {
- val wct = WindowContainerTransaction()
- val options = createNewWindowOptions(callingTask)
- if (options.launchWindowingMode == WINDOWING_MODE_FREEFORM) {
- wct.startTask(requestedTaskId, options.toBundle())
- val taskIdToMinimize =
- bringDesktopAppsToFrontBeforeShowingNewTask(
- callingTask.displayId,
- wct,
+ if (callingTask.isFreeform) {
+ val requestedTaskInfo = shellTaskOrganizer.getRunningTaskInfo(requestedTaskId)
+ if (requestedTaskInfo?.isFreeform == true) {
+ // If requested task is an already open freeform task, just move it to front.
+ moveTaskToFront(requestedTaskId)
+ } else {
+ moveBackgroundTaskToDesktop(
requestedTaskId,
+ WindowContainerTransaction(),
+ DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON,
)
- val exitResult =
- desktopImmersiveController.exitImmersiveIfApplicable(
- wct = wct,
- displayId = callingTask.displayId,
- excludeTaskId = requestedTaskId,
- reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
- )
- val transition = transitions.startTransition(TRANSIT_OPEN, wct, null)
- taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
- addPendingAppLaunchTransition(transition, requestedTaskId, taskIdToMinimize)
- exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
+ }
} else {
+ val options = createNewWindowOptions(callingTask)
val splitPosition = splitScreenController.determineNewInstancePosition(callingTask)
splitScreenController.startTask(
requestedTaskId,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 885f3db..0b91966 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -68,6 +68,8 @@
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.FocusTransitionObserver;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
/**
@@ -90,6 +92,7 @@
private final Transitions mTransitions;
private final Region mExclusionRegion = Region.obtain();
private final InputManager mInputManager;
+ private final WindowDecorViewHostSupplier<WindowDecorViewHost> mWindowDecorViewHostSupplier;
private TaskOperations mTaskOperations;
private FocusTransitionObserver mFocusTransitionObserver;
@@ -130,7 +133,8 @@
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
SyncTransactionQueue syncQueue,
Transitions transitions,
- FocusTransitionObserver focusTransitionObserver) {
+ FocusTransitionObserver focusTransitionObserver,
+ WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier) {
mContext = context;
mMainExecutor = shellExecutor;
mMainHandler = mainHandler;
@@ -143,6 +147,7 @@
mSyncQueue = syncQueue;
mTransitions = transitions;
mFocusTransitionObserver = focusTransitionObserver;
+ mWindowDecorViewHostSupplier = windowDecorViewHostSupplier;
if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
mTaskOperations = new TaskOperations(null, mContext, mSyncQueue);
}
@@ -332,7 +337,8 @@
mMainHandler,
mBgExecutor,
mMainChoreographer,
- mSyncQueue);
+ mSyncQueue,
+ mWindowDecorViewHostSupplier);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
final FluidResizeTaskPositioner taskPositioner =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 112e429..23bb2aa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -58,6 +58,8 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
/**
@@ -90,9 +92,10 @@
Handler handler,
@ShellBackgroundThread ShellExecutor bgExecutor,
Choreographer choreographer,
- SyncTransactionQueue syncQueue) {
- super(context, userContext, displayController, taskOrganizer, handler, taskInfo,
- taskSurface);
+ SyncTransactionQueue syncQueue,
+ @NonNull WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier) {
+ super(context, userContext, displayController, taskOrganizer, taskInfo,
+ taskSurface, windowDecorViewHostSupplier);
mHandler = handler;
mBgExecutor = bgExecutor;
mChoreographer = choreographer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index e8b02dc..08d047a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -139,6 +139,8 @@
import com.android.wm.shell.transition.FocusTransitionObserver;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionRegionListener;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
import com.android.wm.shell.windowdecor.extension.InsetsStateKt;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
@@ -217,6 +219,7 @@
private boolean mInImmersiveMode;
private final String mSysUIPackageName;
private final AssistContentRequester mAssistContentRequester;
+ private final WindowDecorViewHostSupplier<WindowDecorViewHost> mWindowDecorViewHostSupplier;
private final DisplayChangeController.OnDisplayChangingListener mOnDisplayChangingListener;
private final ISystemGestureExclusionListener mGestureExclusionListener =
@@ -260,6 +263,7 @@
InteractionJankMonitor interactionJankMonitor,
AppToWebGenericLinksParser genericLinksParser,
AssistContentRequester assistContentRequester,
+ @NonNull WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier,
MultiInstanceHelper multiInstanceHelper,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
AppHandleEducationController appHandleEducationController,
@@ -289,6 +293,7 @@
desktopImmersiveController,
genericLinksParser,
assistContentRequester,
+ windowDecorViewHostSupplier,
multiInstanceHelper,
new DesktopModeWindowDecoration.Factory(),
new InputMonitorFactory(),
@@ -329,6 +334,7 @@
DesktopImmersiveController desktopImmersiveController,
AppToWebGenericLinksParser genericLinksParser,
AssistContentRequester assistContentRequester,
+ @NonNull WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier,
MultiInstanceHelper multiInstanceHelper,
DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
InputMonitorFactory inputMonitorFactory,
@@ -381,6 +387,7 @@
mWindowDecorCaptionHandleRepository = windowDecorCaptionHandleRepository;
mActivityOrientationChangeHandler = activityOrientationChangeHandler;
mAssistContentRequester = assistContentRequester;
+ mWindowDecorViewHostSupplier = windowDecorViewHostSupplier;
mOnDisplayChangingListener = (displayId, fromRotation, toRotation, displayAreaInfo, t) -> {
DesktopModeWindowDecoration decoration;
RunningTaskInfo taskInfo;
@@ -1623,6 +1630,7 @@
mRootTaskDisplayAreaOrganizer,
mGenericLinksParser,
mAssistContentRequester,
+ mWindowDecorViewHostSupplier,
mMultiInstanceHelper,
mWindowDecorCaptionHandleRepository,
mDesktopModeEventLogger);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 3d0c8a7..6562f38 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -105,6 +105,8 @@
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.shared.multiinstance.ManageWindowsViewContainer;
import com.android.wm.shell.splitscreen.SplitScreenController;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
import com.android.wm.shell.windowdecor.extension.TaskInfoKt;
import com.android.wm.shell.windowdecor.viewholder.AppHandleViewHolder;
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
@@ -127,7 +129,6 @@
*/
public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLinearLayout> {
private static final String TAG = "DesktopModeWindowDecoration";
- private static final int CAPTURED_LINK_TIMEOUT_MS = 7000;
@VisibleForTesting
static final long CLOSE_MAXIMIZE_MENU_DELAY_MS = 150L;
@@ -199,7 +200,6 @@
// being hovered. There's a small delay after stopping the hover, to allow a quick reentry
// to cancel the close.
private final Runnable mCloseMaximizeWindowRunnable = this::closeMaximizeMenu;
- private final Runnable mCapturedLinkExpiredRunnable = this::onCapturedLinkExpired;
private final MultiInstanceHelper mMultiInstanceHelper;
private final WindowDecorCaptionHandleRepository mWindowDecorCaptionHandleRepository;
private final DesktopUserRepositories mDesktopUserRepositories;
@@ -221,6 +221,7 @@
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
AppToWebGenericLinksParser genericLinksParser,
AssistContentRequester assistContentRequester,
+ @NonNull WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier,
MultiInstanceHelper multiInstanceHelper,
WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
DesktopModeEventLogger desktopModeEventLogger) {
@@ -232,6 +233,7 @@
WindowContainerTransaction::new, SurfaceControl::new, new WindowManagerWrapper(
context.getSystemService(WindowManager.class)),
new SurfaceControlViewHostFactory() {},
+ windowDecorViewHostSupplier,
DefaultMaximizeMenuFactory.INSTANCE,
DefaultHandleMenuFactory.INSTANCE, multiInstanceHelper,
windowDecorCaptionHandleRepository, desktopModeEventLogger);
@@ -260,15 +262,16 @@
Supplier<SurfaceControl> surfaceControlSupplier,
WindowManagerWrapper windowManagerWrapper,
SurfaceControlViewHostFactory surfaceControlViewHostFactory,
+ @NonNull WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier,
MaximizeMenuFactory maximizeMenuFactory,
HandleMenuFactory handleMenuFactory,
MultiInstanceHelper multiInstanceHelper,
WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
DesktopModeEventLogger desktopModeEventLogger) {
- super(context, userContext, displayController, taskOrganizer, handler, taskInfo,
+ super(context, userContext, displayController, taskOrganizer, taskInfo,
taskSurface, surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
windowContainerTransactionSupplier, surfaceControlSupplier,
- surfaceControlViewHostFactory, desktopModeEventLogger);
+ surfaceControlViewHostFactory, windowDecorViewHostSupplier, desktopModeEventLogger);
mSplitScreenController = splitScreenController;
mHandler = handler;
mBgExecutor = bgExecutor;
@@ -548,22 +551,12 @@
return;
}
mCapturedLink = new CapturedLink(capturedLink, timeStamp);
- mHandler.postDelayed(mCapturedLinkExpiredRunnable, CAPTURED_LINK_TIMEOUT_MS);
- }
-
- private void onCapturedLinkExpired() {
- mHandler.removeCallbacks(mCapturedLinkExpiredRunnable);
- if (mCapturedLink != null) {
- mCapturedLink.setExpired();
- }
}
@Nullable
private Intent getBrowserLink() {
final Uri browserLink;
- // If the captured link is available and has not expired, return the captured link.
- // Otherwise, return the generic link which is set to null if a generic link is unavailable.
- if (mCapturedLink != null && !mCapturedLink.mExpired) {
+ if (isCapturedLinkAvailable()) {
browserLink = mCapturedLink.mUri;
} else if (mWebUri != null) {
browserLink = mWebUri;
@@ -675,7 +668,13 @@
}
private boolean isCapturedLinkAvailable() {
- return mCapturedLink != null && !mCapturedLink.mExpired;
+ return mCapturedLink != null && !mCapturedLink.mUsed;
+ }
+
+ private void onCapturedLinkUsed() {
+ if (mCapturedLink != null) {
+ mCapturedLink.setUsed();
+ }
}
private void notifyNoCaptionHandle() {
@@ -1365,7 +1364,7 @@
/* onAspectRatioSettingsClickListener= */ mOnChangeAspectRatioClickListener,
/* openInBrowserClickListener= */ (intent) -> {
mOpenInBrowserClickListener.accept(intent);
- onCapturedLinkExpired();
+ onCapturedLinkUsed();
if (Flags.enableDesktopWindowingAppToWebEducationIntegration()) {
mWindowDecorCaptionHandleRepository.onAppToWebUsage();
}
@@ -1766,6 +1765,8 @@
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
AppToWebGenericLinksParser genericLinksParser,
AssistContentRequester assistContentRequester,
+ @NonNull WindowDecorViewHostSupplier<WindowDecorViewHost>
+ windowDecorViewHostSupplier,
MultiInstanceHelper multiInstanceHelper,
WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
DesktopModeEventLogger desktopModeEventLogger) {
@@ -1786,6 +1787,7 @@
rootTaskDisplayAreaOrganizer,
genericLinksParser,
assistContentRequester,
+ windowDecorViewHostSupplier,
multiInstanceHelper,
windowDecorCaptionHandleRepository,
desktopModeEventLogger);
@@ -1796,16 +1798,15 @@
static class CapturedLink {
private final long mTimeStamp;
private final Uri mUri;
- private boolean mExpired;
+ private boolean mUsed;
CapturedLink(@NonNull Uri uri, long timeStamp) {
mUri = uri;
mTimeStamp = timeStamp;
- mExpired = false;
}
- void setExpired() {
- mExpired = true;
+ private void setUsed() {
+ mUsed = true;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 261d400..5d1bedb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -39,7 +39,6 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Binder;
-import android.os.Handler;
import android.os.Trace;
import android.view.Display;
import android.view.InsetsSource;
@@ -59,10 +58,11 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
-import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams.OccludingCaptionElement;
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewHostViewContainer;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
import com.android.wm.shell.windowdecor.extension.InsetsStateKt;
import java.util.ArrayList;
@@ -90,10 +90,10 @@
implements AutoCloseable {
/**
- * The Z-order of {@link #mCaptionContainerSurface}.
+ * The Z-order of the caption surface.
* <p>
* We use {@link #mDecorationContainerSurface} to define input window for task resizing; by
- * layering it in front of {@link #mCaptionContainerSurface}, we can allow it to handle input
+ * layering it in front of the caption surface, we can allow it to handle input
* prior to caption view itself, treating corner inputs as resize events rather than
* repositioning.
*/
@@ -102,7 +102,7 @@
* The Z-order of the task input sink in {@link DragPositioningCallback}.
* <p>
* This task input sink is used to prevent undesired dispatching of motion events out of task
- * bounds; by layering it behind {@link #mCaptionContainerSurface}, we allow captions to handle
+ * bounds; by layering it behind the caption surface, we allow captions to handle
* input events first.
*/
static final int INPUT_SINK_Z_ORDER = -2;
@@ -123,12 +123,13 @@
final @NonNull Context mUserContext;
final @NonNull DisplayController mDisplayController;
final @NonNull DesktopModeEventLogger mDesktopModeEventLogger;
- private final @ShellMainThread Handler mMainHandler;
final ShellTaskOrganizer mTaskOrganizer;
final Supplier<SurfaceControl.Builder> mSurfaceControlBuilderSupplier;
final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier;
final Supplier<WindowContainerTransaction> mWindowContainerTransactionSupplier;
final SurfaceControlViewHostFactory mSurfaceControlViewHostFactory;
+ @NonNull private final WindowDecorViewHostSupplier<WindowDecorViewHost>
+ mWindowDecorViewHostSupplier;
private final DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
new DisplayController.OnDisplaysChangedListener() {
@Override
@@ -153,9 +154,7 @@
Display mDisplay;
SurfaceControl mDecorationContainerSurface;
- SurfaceControl mCaptionContainerSurface;
- private CaptionWindowlessWindowManager mCaptionWindowManager;
- private SurfaceControlViewHost mViewHost;
+ private WindowDecorViewHost mViewHost;
private Configuration mWindowDecorConfig;
TaskDragResizer mTaskDragResizer;
boolean mIsCaptionVisible;
@@ -170,20 +169,19 @@
private final Binder mOwner = new Binder();
private final float[] mTmpColor = new float[3];
- private Runnable mCurrentUpdateViewHostRunnable;
-
WindowDecoration(
Context context,
@NonNull Context userContext,
DisplayController displayController,
ShellTaskOrganizer taskOrganizer,
- @ShellMainThread Handler mainHandler,
RunningTaskInfo taskInfo,
- SurfaceControl taskSurface) {
- this(context, userContext, displayController, taskOrganizer, mainHandler, taskInfo,
+ SurfaceControl taskSurface,
+ @NonNull WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier) {
+ this(context, userContext, displayController, taskOrganizer, taskInfo,
taskSurface, SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
WindowContainerTransaction::new, SurfaceControl::new,
- new SurfaceControlViewHostFactory() {}, new DesktopModeEventLogger());
+ new SurfaceControlViewHostFactory() {}, windowDecorViewHostSupplier,
+ new DesktopModeEventLogger());
}
WindowDecoration(
@@ -191,7 +189,6 @@
@NonNull Context userContext,
@NonNull DisplayController displayController,
ShellTaskOrganizer taskOrganizer,
- @ShellMainThread Handler mainHandler,
RunningTaskInfo taskInfo,
@NonNull SurfaceControl taskSurface,
Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
@@ -199,13 +196,13 @@
Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
Supplier<SurfaceControl> surfaceControlSupplier,
SurfaceControlViewHostFactory surfaceControlViewHostFactory,
+ @NonNull WindowDecorViewHostSupplier<WindowDecorViewHost> windowDecorViewHostSupplier,
@NonNull DesktopModeEventLogger desktopModeEventLogger
) {
mContext = context;
mUserContext = userContext;
mDisplayController = displayController;
mTaskOrganizer = taskOrganizer;
- mMainHandler = mainHandler;
mTaskInfo = taskInfo;
mTaskSurface = cloneSurfaceControl(taskSurface, surfaceControlSupplier);
mDesktopModeEventLogger = desktopModeEventLogger;
@@ -213,6 +210,7 @@
mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier;
mWindowContainerTransactionSupplier = windowContainerTransactionSupplier;
mSurfaceControlViewHostFactory = surfaceControlViewHostFactory;
+ mWindowDecorViewHostSupplier = windowDecorViewHostSupplier;
mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId);
final InsetsState insetsState = mDisplayController.getInsetsState(mTaskInfo.displayId);
mIsStatusBarVisible = insetsState != null
@@ -292,43 +290,20 @@
outResult.mCaptionY = 0;
outResult.mCaptionTopPadding = params.mCaptionTopPadding;
+ Trace.beginSection("relayout-createViewHostIfNeeded");
+ createViewHostIfNeeded(mDecorWindowContext, mDisplay);
+ Trace.endSection();
+
Trace.beginSection("WindowDecoration#relayout-updateSurfacesAndInsets");
+ final SurfaceControl captionSurface = mViewHost.getSurfaceControl();
updateDecorationContainerSurface(startT, outResult);
- final SurfaceControl captionSurface = getOrCreateCaptionSurface();
updateCaptionContainerSurface(captionSurface, startT, outResult);
updateCaptionInsets(params, wct, outResult, taskBounds);
updateTaskSurface(params, startT, finishT, outResult);
Trace.endSection();
Trace.beginSection("WindowDecoration#relayout-updateViewHost");
- clearCurrentViewHostRunnable();
- if (params.mAsyncViewHost) {
- mCurrentUpdateViewHostRunnable = () -> updateViewHost(params, startT, outResult);
- mMainHandler.post(mCurrentUpdateViewHostRunnable);
- } else {
- updateViewHost(params, startT, outResult);
- }
- Trace.endSection();
-
- Trace.endSection(); // WindowDecoration#relayout
- }
-
- private void clearCurrentViewHostRunnable() {
- if (mCurrentUpdateViewHostRunnable != null) {
- mMainHandler.removeCallbacks(mCurrentUpdateViewHostRunnable);
- mCurrentUpdateViewHostRunnable = null;
- }
- }
-
- private void updateViewHost(RelayoutParams params, SurfaceControl.Transaction startT,
- RelayoutResult<T> outResult) {
- createCaptionWindowManagerIfNeeded();
- Trace.beginSection("updateViewHost-createViewHostIfNeeded");
- final boolean firstLayout = createViewHostIfNeeded(mDecorWindowContext, mDisplay);
- Trace.endSection();
-
outResult.mRootView.setPadding(0, params.mCaptionTopPadding, 0, 0);
- mCaptionWindowManager.setConfiguration(mTaskInfo.getConfiguration());
final Rect localCaptionBounds = new Rect(
outResult.mCaptionX,
outResult.mCaptionY,
@@ -337,50 +312,21 @@
final Region touchableRegion = params.mLimitTouchRegionToSystemAreas
? calculateLimitedTouchableRegion(params, localCaptionBounds)
: null;
- if (params.mLimitTouchRegionToSystemAreas) {
- mCaptionWindowManager.setTouchRegion(mViewHost, touchableRegion);
- }
- if (touchableRegion != null) {
- touchableRegion.recycle();
- }
- updateViewHierarchy(params, outResult, startT, firstLayout);
+ updateViewHierarchy(params, outResult, startT, touchableRegion);
+ Trace.endSection();
+
+ Trace.endSection(); // WindowDecoration#relayout
}
- private SurfaceControl getOrCreateCaptionSurface() {
- if (mCaptionContainerSurface == null) {
- final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
- mCaptionContainerSurface = builder
- .setName("Caption container of Task=" + mTaskInfo.taskId)
- .setContainerLayer()
- .setParent(mDecorationContainerSurface)
- .setCallsite("WindowDecoration.updateCaptionContainerSurface")
- .build();
- }
- return mCaptionContainerSurface;
- }
-
- private boolean createViewHostIfNeeded(@NonNull Context context, @NonNull Display display) {
+ private void createViewHostIfNeeded(@NonNull Context context, @NonNull Display display) {
if (mViewHost == null) {
- mViewHost = mSurfaceControlViewHostFactory.create(context, display,
- mCaptionWindowManager);
- Trace.endSection();
- return true;
- }
- return false;
- }
-
- private void createCaptionWindowManagerIfNeeded() {
- if (mCaptionWindowManager == null) {
- // Put caption under a container surface because ViewRootImpl sets the destination frame
- // of windowless window layers and BLASTBufferQueue#update() doesn't support offset.
- mCaptionWindowManager = new CaptionWindowlessWindowManager(
- mTaskInfo.getConfiguration(), mCaptionContainerSurface);
+ mViewHost = mWindowDecorViewHostSupplier.acquire(context, display);
}
}
private void updateViewHierarchy(@NonNull RelayoutParams params,
@NonNull RelayoutResult<T> outResult, @NonNull SurfaceControl.Transaction startT,
- boolean firstLayout) {
+ @Nullable Region touchableRegion) {
Trace.beginSection("WindowDecoration#updateViewHierarchy");
final WindowManager.LayoutParams lp =
new WindowManager.LayoutParams(
@@ -392,16 +338,15 @@
lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
lp.setTrustedOverlay();
lp.inputFeatures = params.mInputFeatures;
- if (params.mApplyStartTransactionOnDraw) {
- if (params.mAsyncViewHost) {
+ if (params.mAsyncViewHost) {
+ if (params.mApplyStartTransactionOnDraw) {
throw new IllegalArgumentException("Cannot use sync draw tx with async relayout");
}
- mViewHost.getRootSurfaceControl().applyTransactionOnDraw(startT);
- }
- if (firstLayout) {
- mViewHost.setView(outResult.mRootView, lp);
+ mViewHost.updateViewAsync(outResult.mRootView, lp, mTaskInfo.configuration,
+ touchableRegion);
} else {
- mViewHost.relayout(lp);
+ mViewHost.updateView(outResult.mRootView, lp, mTaskInfo.configuration,
+ touchableRegion, params.mApplyStartTransactionOnDraw ? startT : null);
}
Trace.endSection();
}
@@ -719,18 +664,11 @@
}
void releaseViews(WindowContainerTransaction wct) {
- if (mViewHost != null) {
- mViewHost.release();
- mViewHost = null;
- }
-
- mCaptionWindowManager = null;
-
final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
boolean released = false;
- if (mCaptionContainerSurface != null) {
- t.remove(mCaptionContainerSurface);
- mCaptionContainerSurface = null;
+ if (mViewHost != null) {
+ mWindowDecorViewHostSupplier.release(mViewHost, t);
+ mViewHost = null;
released = true;
}
@@ -753,7 +691,6 @@
@Override
public void close() {
Trace.beginSection("WindowDecoration#close");
- clearCurrentViewHostRunnable();
mDisplayController.removeDisplayWindowListener(mOnDisplaysChangedListener);
final WindowContainerTransaction wct = mWindowContainerTransactionSupplier.get();
releaseViews(wct);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHost.kt
index c470eef..50aa21e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHost.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHost.kt
@@ -17,6 +17,7 @@
import android.content.Context
import android.content.res.Configuration
+import android.graphics.Region
import android.view.Display
import android.view.SurfaceControl
import android.view.SurfaceControlViewHost
@@ -59,7 +60,7 @@
.setCallsite("DefaultWindowDecorViewHost#init")
.build()
- private var wwm: WindowlessWindowManager? = null
+ private var wwm: WindowDecorWindowlessWindowManager? = null
@VisibleForTesting var viewHost: SurfaceControlViewHost? = null
private var currentUpdateJob: Job? = null
@@ -70,11 +71,12 @@
view: View,
attrs: WindowManager.LayoutParams,
configuration: Configuration,
+ touchableRegion: Region?,
onDrawTransaction: SurfaceControl.Transaction?,
) {
Trace.beginSection("DefaultWindowDecorViewHost#updateView")
clearCurrentUpdateJob()
- updateViewHost(view, attrs, configuration, onDrawTransaction)
+ updateViewHost(view, attrs, configuration, touchableRegion, onDrawTransaction)
Trace.endSection()
}
@@ -82,12 +84,19 @@
view: View,
attrs: WindowManager.LayoutParams,
configuration: Configuration,
+ touchableRegion: Region?,
) {
Trace.beginSection("DefaultWindowDecorViewHost#updateViewAsync")
clearCurrentUpdateJob()
currentUpdateJob =
mainScope.launch {
- updateViewHost(view, attrs, configuration, onDrawTransaction = null)
+ updateViewHost(
+ view,
+ attrs,
+ configuration,
+ touchableRegion,
+ onDrawTransaction = null
+ )
}
Trace.endSection()
}
@@ -102,13 +111,13 @@
view: View,
attrs: WindowManager.LayoutParams,
configuration: Configuration,
+ touchableRegion: Region?,
onDrawTransaction: SurfaceControl.Transaction?,
) {
Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost")
if (wwm == null) {
- wwm = WindowlessWindowManager(configuration, rootSurface, null)
+ wwm = WindowDecorWindowlessWindowManager(configuration, rootSurface)
}
- requireWindowlessWindowManager().setConfiguration(configuration)
if (viewHost == null) {
viewHost =
surfaceControlViewHostFactory.invoke(
@@ -118,6 +127,10 @@
"DefaultWindowDecorViewHost#updateViewHost",
)
}
+ requireWindowlessWindowManager().apply {
+ setConfiguration(configuration)
+ setTouchRegion(requireViewHost(), touchableRegion)
+ }
onDrawTransaction?.let { requireViewHost().rootSurfaceControl.applyTransactionOnDraw(it) }
if (requireViewHost().view == null) {
Trace.beginSection("DefaultWindowDecorViewHost#updateViewHost-setView")
@@ -137,7 +150,7 @@
currentUpdateJob = null
}
- private fun requireWindowlessWindowManager(): WindowlessWindowManager {
+ private fun requireWindowlessWindowManager(): WindowDecorWindowlessWindowManager {
return wwm ?: error("Expected non-null windowless window manager")
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHostSupplier.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHostSupplier.kt
index 27ffd6c..7821619 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHostSupplier.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/DefaultWindowDecorViewHostSupplier.kt
@@ -24,14 +24,15 @@
/**
* A supplier of [DefaultWindowDecorViewHost]s. It creates a new one every time one is requested.
*/
-class DefaultWindowDecorViewHostSupplier(@ShellMainThread private val mainScope: CoroutineScope) :
- WindowDecorViewHostSupplier<DefaultWindowDecorViewHost> {
+class DefaultWindowDecorViewHostSupplier(
+ @ShellMainThread private val mainScope: CoroutineScope
+) : WindowDecorViewHostSupplier<WindowDecorViewHost> {
- override fun acquire(context: Context, display: Display): DefaultWindowDecorViewHost {
+ override fun acquire(context: Context, display: Display): WindowDecorViewHost {
return DefaultWindowDecorViewHost(context, mainScope, display)
}
- override fun release(viewHost: DefaultWindowDecorViewHost, t: SurfaceControl.Transaction) {
+ override fun release(viewHost: WindowDecorViewHost, t: SurfaceControl.Transaction) {
viewHost.release(t)
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorViewHost.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorViewHost.kt
index 7c1479e..2dcbbac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorViewHost.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorViewHost.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.windowdecor.common.viewhost
import android.content.res.Configuration
+import android.graphics.Region
import android.view.SurfaceControl
import android.view.View
import android.view.WindowManager
@@ -34,11 +35,17 @@
view: View,
attrs: WindowManager.LayoutParams,
configuration: Configuration,
- onDrawTransaction: SurfaceControl.Transaction?,
+ touchableRegion: Region? = null,
+ onDrawTransaction: SurfaceControl.Transaction? = null,
)
/** Asynchronously update the view hierarchy of this view host. */
- fun updateViewAsync(view: View, attrs: WindowManager.LayoutParams, configuration: Configuration)
+ fun updateViewAsync(
+ view: View,
+ attrs: WindowManager.LayoutParams,
+ configuration: Configuration,
+ touchableRegion: Region? = null,
+ )
/** Releases the underlying [View] hierarchy and removes the backing [SurfaceControl]. */
fun release(t: SurfaceControl.Transaction)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorWindowlessWindowManager.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorWindowlessWindowManager.kt
new file mode 100644
index 0000000..fbe8c6c8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/viewhost/WindowDecorWindowlessWindowManager.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.wm.shell.windowdecor.common.viewhost
+
+import android.content.res.Configuration
+import android.graphics.Region
+import android.view.SurfaceControl
+import android.view.SurfaceControlViewHost
+import android.view.WindowlessWindowManager
+
+/**
+ * A [WindowlessWindowManager] for the window decor caption that allows customizing the touchable
+ * region.
+ */
+class WindowDecorWindowlessWindowManager(
+ configuration: Configuration,
+ rootSurface: SurfaceControl,
+) : WindowlessWindowManager(configuration, rootSurface, /* hostInputTransferToken= */ null) {
+
+ /** Set the view host's touchable region. */
+ fun setTouchRegion(viewHost: SurfaceControlViewHost, region: Region?) {
+ setTouchRegion(viewHost.windowToken.asBinder(), region)
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index c10434a..8e21071 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -3305,44 +3305,41 @@
setUpLandscapeDisplay()
val task = setUpFreeformTask()
val taskToRequest = setUpFreeformTask()
- val wctCaptor = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
runOpenInstance(task, taskToRequest.taskId)
- verify(transitions).startTransition(anyInt(), wctCaptor.capture(), anyOrNull())
- assertThat(ActivityOptions.fromBundle(wctCaptor.value.hierarchyOps[0].launchOptions)
- .launchWindowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+ verify(desktopMixedTransitionHandler).startLaunchTransition(anyInt(), any(), anyInt(),
+ anyOrNull(), anyOrNull())
+ val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_TO_FRONT)
+ assertThat(wct.hierarchyOps).hasSize(1)
+ wct.assertReorderAt(index = 0, taskToRequest)
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES)
fun openInstance_fromFreeform_minimizesIfNeeded() {
setUpLandscapeDisplay()
- val homeTask = setUpHomeTask()
val freeformTasks = (1..MAX_TASK_LIMIT + 1).map { _ -> setUpFreeformTask() }
val oldestTask = freeformTasks.first()
val newestTask = freeformTasks.last()
+ val transition = Binder()
+ val wctCaptor = argumentCaptor<WindowContainerTransaction>()
+ whenever(desktopMixedTransitionHandler.startLaunchTransition(anyInt(), wctCaptor.capture(),
+ anyInt(), anyOrNull(), anyOrNull()
+ ))
+ .thenReturn(transition)
+
runOpenInstance(newestTask, freeformTasks[1].taskId)
- val wct = getLatestWct(type = TRANSIT_OPEN)
- // Home is moved to front of everything.
- assertThat(
- wct.hierarchyOps.any { hop ->
- hop.container == homeTask.token.asBinder() && hop.toTop
- }
- ).isTrue()
- // And the oldest task isn't moved in front of home, effectively minimizing it.
- assertThat(
- wct.hierarchyOps.none { hop ->
- hop.container == oldestTask.token.asBinder() && hop.toTop
- }
- ).isTrue()
+ val wct = wctCaptor.firstValue
+ assertThat(wct.hierarchyOps.size).isEqualTo(2) // move-to-front + minimize
+ wct.assertReorderAt(0, freeformTasks[1], toTop = true)
+ wct.assertReorderAt(1, oldestTask, toTop = false)
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES)
fun openInstance_fromFreeform_exitsImmersiveIfNeeded() {
setUpLandscapeDisplay()
- val homeTask = setUpHomeTask()
val freeformTask = setUpFreeformTask()
val immersiveTask = setUpFreeformTask()
taskRepository.setTaskInFullImmersiveState(
@@ -3352,11 +3349,13 @@
)
val runOnStartTransit = RunOnStartTransitionCallback()
val transition = Binder()
- whenever(transitions.startTransition(eq(TRANSIT_OPEN), any(), anyOrNull()))
+ whenever(desktopMixedTransitionHandler.startLaunchTransition(anyInt(), any(), anyInt(),
+ anyOrNull(), anyOrNull()
+ ))
.thenReturn(transition)
whenever(mMockDesktopImmersiveController
.exitImmersiveIfApplicable(
- any(), eq(immersiveTask.displayId), eq(freeformTask.taskId), any()))
+ any(), eq(DEFAULT_DISPLAY), eq(freeformTask.taskId), any()))
.thenReturn(
ExitResult.Exit(
exitingTask = immersiveTask.taskId,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
index afd4607..dce44b7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
@@ -74,6 +74,8 @@
import com.android.wm.shell.util.StubTransaction
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener
import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder
import org.junit.After
import org.junit.Rule
@@ -131,6 +133,8 @@
protected val mockAssistContentRequester = mock<AssistContentRequester>()
protected val bgExecutor = TestShellExecutor()
protected val mockMultiInstanceHelper = mock<MultiInstanceHelper>()
+ private val mockWindowDecorViewHostSupplier =
+ mock<WindowDecorViewHostSupplier<WindowDecorViewHost>>()
protected val mockTasksLimiter = mock<DesktopTasksLimiter>()
protected val mockFreeformTaskTransitionStarter = mock<FreeformTaskTransitionStarter>()
protected val mockActivityOrientationChangeHandler =
@@ -193,6 +197,7 @@
mockDesktopImmersiveController,
mockGenericLinksParser,
mockAssistContentRequester,
+ mockWindowDecorViewHostSupplier,
mockMultiInstanceHelper,
mockDesktopModeWindowDecorFactory,
mockInputMonitorFactory,
@@ -289,7 +294,7 @@
whenever(
mockDesktopModeWindowDecorFactory.create(
any(), any(), any(), any(), any(), any(), eq(task), any(), any(), any(), any(),
- any(), any(), any(), any(), any(), any(), any(), any())
+ any(), any(), any(), any(), any(), any(), any(), any(), any())
).thenReturn(decoration)
decoration.mTaskInfo = task
whenever(decoration.user).thenReturn(mockUserHandle)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index f4cd8e0..5d5d1f2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -39,7 +39,6 @@
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
@@ -114,6 +113,8 @@
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.windowdecor.WindowDecoration.RelayoutParams;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
import com.android.wm.shell.windowdecor.viewholder.AppHeaderViewHolder;
import kotlin.Unit;
@@ -186,6 +187,10 @@
@Mock
private AttachedSurfaceControl mMockRootSurfaceControl;
@Mock
+ private WindowDecorViewHostSupplier<WindowDecorViewHost> mMockWindowDecorViewHostSupplier;
+ @Mock
+ private WindowDecorViewHost mMockWindowDecorViewHost;
+ @Mock
private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory;
@Mock
private TypedArray mMockRoundedCornersRadiusArray;
@@ -275,6 +280,9 @@
any())).thenReturn(mMockAppHeaderViewHolder);
when(mMockDesktopUserRepositories.getCurrent()).thenReturn(mDesktopRepository);
when(mMockDesktopUserRepositories.getProfile(anyInt())).thenReturn(mDesktopRepository);
+ when(mMockWindowDecorViewHostSupplier.acquire(any(), eq(defaultDisplay)))
+ .thenReturn(mMockWindowDecorViewHost);
+ when(mMockWindowDecorViewHost.getSurfaceControl()).thenReturn(mock(SurfaceControl.class));
}
@After
@@ -1327,68 +1335,41 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB)
- public void capturedLink_postsOnCapturedLinkExpiredRunnable() {
- final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */);
- final DesktopModeWindowDecoration decor = createWindowDecoration(
- taskInfo, TEST_URI1 /* captured link */, null /* web uri */,
- null /* generic link */);
- final ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
-
- // Run runnable to set captured link to expired
- verify(mMockHandler).postDelayed(runnableArgument.capture(), anyLong());
- runnableArgument.getValue().run();
-
- // Verify captured link is no longer valid by verifying link is not set as handle menu
- // browser link.
- createHandleMenu(decor);
- verifyHandleMenuCreated(null /* uri */);
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB)
public void capturedLink_capturedLinkNotResetToSameLink() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */);
final DesktopModeWindowDecoration decor = createWindowDecoration(
taskInfo, TEST_URI1 /* captured link */, null /* web uri */,
null /* generic link */);
- final ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
+ final ArgumentCaptor<Function1<Intent, Unit>> openInBrowserCaptor =
+ ArgumentCaptor.forClass(Function1.class);
- // Run runnable to set captured link to expired
- verify(mMockHandler).postDelayed(runnableArgument.capture(), anyLong());
- runnableArgument.getValue().run();
+ createHandleMenu(decor);
+ verify(mMockHandleMenu).show(any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ any(),
+ openInBrowserCaptor.capture(),
+ any(),
+ any(),
+ any(),
+ anyBoolean()
+ );
+ // Run runnable to set captured link to used
+ openInBrowserCaptor.getValue().invoke(new Intent(Intent.ACTION_MAIN, TEST_URI1));
// Relayout decor with same captured link
decor.relayout(taskInfo, true /* hasGlobalFocus */, mExclusionRegion);
- // Verify handle menu's browser link not set to captured link since link is expired
+ // Verify handle menu's browser link not set to captured link since link is already used
createHandleMenu(decor);
verifyHandleMenuCreated(null /* uri */);
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB)
- public void capturedLink_capturedLinkStillUsedIfExpiredAfterHandleMenuCreation() {
- final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */);
- final DesktopModeWindowDecoration decor = createWindowDecoration(
- taskInfo, TEST_URI1 /* captured link */, null /* web uri */,
- null /* generic link */);
- final ArgumentCaptor<Runnable> runnableArgument = ArgumentCaptor.forClass(Runnable.class);
-
- // Create handle menu before link expires
- createHandleMenu(decor);
-
- // Run runnable to set captured link to expired
- verify(mMockHandler).postDelayed(runnableArgument.capture(), anyLong());
- runnableArgument.getValue().run();
-
- // Verify handle menu's browser link is set to captured link since menu was opened before
- // captured link expired
- verifyHandleMenuCreated(TEST_URI1);
- }
-
- @Test
- @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_APP_TO_WEB)
- public void capturedLink_capturedLinkExpiresAfterClick() {
+ public void capturedLink_capturedLinkSetToUsedAfterClick() {
final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(true /* visible */);
final DesktopModeWindowDecoration decor = createWindowDecoration(
taskInfo, TEST_URI1 /* captured link */, null /* web uri */,
@@ -1750,7 +1731,7 @@
mMockGenericLinksParser, mMockAssistContentRequester, SurfaceControl.Builder::new,
mMockTransactionSupplier, WindowContainerTransaction::new, SurfaceControl::new,
new WindowManagerWrapper(mMockWindowManager), mMockSurfaceControlViewHostFactory,
- maximizeMenuFactory, mMockHandleMenuFactory,
+ mMockWindowDecorViewHostSupplier, maximizeMenuFactory, mMockHandleMenuFactory,
mMockMultiInstanceHelper, mMockCaptionHandleRepository, mDesktopModeEventLogger);
windowDecor.setCaptionListeners(mMockTouchEventListener, mMockTouchEventListener,
mMockTouchEventListener, mMockTouchEventListener);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 3a82ff6..d969346 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -89,6 +89,8 @@
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.tests.R;
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalViewContainer;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
+import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
import org.junit.Before;
import org.junit.Rule;
@@ -131,6 +133,10 @@
@Mock
private WindowDecoration.SurfaceControlViewHostFactory mMockSurfaceControlViewHostFactory;
@Mock
+ private WindowDecorViewHostSupplier<WindowDecorViewHost> mMockWindowDecorViewHostSupplier;
+ @Mock
+ private WindowDecorViewHost mMockWindowDecorViewHost;
+ @Mock
private SurfaceControlViewHost mMockSurfaceControlViewHost;
@Mock
private AttachedSurfaceControl mMockRootSurfaceControl;
@@ -180,6 +186,10 @@
// Add status bar inset so that WindowDecoration does not think task is in immersive mode
mInsetsState.getOrCreateSource(STATUS_BAR_INSET_SOURCE_ID, statusBars()).setVisible(true);
doReturn(mInsetsState).when(mMockDisplayController).getInsetsState(anyInt());
+
+ when(mMockWindowDecorViewHostSupplier.acquire(any(), any()))
+ .thenReturn(mMockWindowDecorViewHost);
+ when(mMockWindowDecorViewHost.getSurfaceControl()).thenReturn(mock(SurfaceControl.class));
}
@Test
@@ -236,10 +246,6 @@
final SurfaceControl.Builder decorContainerSurfaceBuilder =
createMockSurfaceControlBuilder(decorContainerSurface);
mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
- final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
- final SurfaceControl.Builder captionContainerSurfaceBuilder =
- createMockSurfaceControlBuilder(captionContainerSurface);
- mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
.setDisplayId(Display.DEFAULT_DISPLAY)
@@ -260,18 +266,19 @@
verify(mMockSurfaceControlStartT).setTrustedOverlay(decorContainerSurface, true);
verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 300, 100);
- verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
- verify(captionContainerSurfaceBuilder).setContainerLayer();
+ final SurfaceControl captionContainerSurface = mMockWindowDecorViewHost.getSurfaceControl();
+ verify(mMockSurfaceControlStartT).reparent(captionContainerSurface, decorContainerSurface);
verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
verify(mMockSurfaceControlStartT).show(captionContainerSurface);
- verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any());
-
- verify(mMockSurfaceControlViewHost)
- .setView(same(mMockView),
- argThat(lp -> lp.height == 64
- && lp.width == 300
- && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0));
+ verify(mMockWindowDecorViewHost).updateView(
+ same(mMockView),
+ argThat(lp -> lp.height == 64
+ && lp.width == 300
+ && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0),
+ eq(taskInfo.configuration),
+ any(),
+ eq(null) /* onDrawTransaction */);
verify(mMockView).setTaskFocusState(true);
verify(mMockWindowContainerTransaction).addInsetsSource(
eq(taskInfo.token),
@@ -300,10 +307,6 @@
final SurfaceControl.Builder decorContainerSurfaceBuilder =
createMockSurfaceControlBuilder(decorContainerSurface);
mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
- final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
- final SurfaceControl.Builder captionContainerSurfaceBuilder =
- createMockSurfaceControlBuilder(captionContainerSurface);
- mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
mMockSurfaceControlTransactions.add(t);
@@ -326,7 +329,7 @@
windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
- verify(mMockSurfaceControlViewHost, never()).release();
+ verify(mMockWindowDecorViewHost, never()).release(any());
verify(t, never()).apply();
verify(mMockWindowContainerTransaction, never())
.removeInsetsSource(eq(taskInfo.token), any(), anyInt(), anyInt());
@@ -336,9 +339,8 @@
taskInfo.isVisible = false;
windowDecor.relayout(taskInfo, false /* hasGlobalFocus */);
- final InOrder releaseOrder = inOrder(t2, mMockSurfaceControlViewHost);
- releaseOrder.verify(mMockSurfaceControlViewHost).release();
- releaseOrder.verify(t2).remove(captionContainerSurface);
+ final InOrder releaseOrder = inOrder(t2, mMockWindowDecorViewHostSupplier);
+ releaseOrder.verify(mMockWindowDecorViewHostSupplier).release(mMockWindowDecorViewHost, t2);
releaseOrder.verify(t2).remove(decorContainerSurface);
releaseOrder.verify(t2).apply();
// Expect to remove two insets sources, the caption insets and the mandatory gesture insets.
@@ -386,8 +388,8 @@
verify(mMockDisplayController).removeDisplayWindowListener(same(listener));
assertThat(mRelayoutResult.mRootView).isSameInstanceAs(mMockView);
- verify(mMockSurfaceControlViewHostFactory).create(any(), eq(mockDisplay), any());
- verify(mMockSurfaceControlViewHost).setView(same(mMockView), any());
+ verify(mMockWindowDecorViewHostSupplier).acquire(any(), eq(mockDisplay));
+ verify(mMockWindowDecorViewHost).updateView(same(mMockView), any(), any(), any(), any());
}
@Test
@@ -400,10 +402,6 @@
final SurfaceControl.Builder decorContainerSurfaceBuilder =
createMockSurfaceControlBuilder(decorContainerSurface);
mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
- final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
- final SurfaceControl.Builder captionContainerSurfaceBuilder =
- createMockSurfaceControlBuilder(captionContainerSurface);
- mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
mMockSurfaceControlTransactions.add(t);
@@ -439,8 +437,7 @@
windowDecor.mDecorWindowContext.getResources(), mRelayoutParams.mCaptionHeightId);
verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, width, height);
verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface);
- verify(mMockSurfaceControlViewHostFactory, Mockito.times(2))
- .create(any(), eq(defaultDisplay), any());
+ verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any());
}
@Test
@@ -453,10 +450,6 @@
final SurfaceControl.Builder decorContainerSurfaceBuilder =
createMockSurfaceControlBuilder(decorContainerSurface);
mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
- final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
- final SurfaceControl.Builder captionContainerSurfaceBuilder =
- createMockSurfaceControlBuilder(captionContainerSurface);
- mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
mMockSurfaceControlTransactions.add(t);
@@ -475,8 +468,8 @@
windowDecor.relayout(taskInfo, true /* hasGlobalFocus */);
- verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
- verify(captionContainerSurfaceBuilder).setContainerLayer();
+ final SurfaceControl captionContainerSurface = mMockWindowDecorViewHost.getSurfaceControl();
+ verify(mMockSurfaceControlStartT).reparent(captionContainerSurface, decorContainerSurface);
// Width of the captionContainerSurface should match the width of TASK_BOUNDS
verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
verify(mMockSurfaceControlStartT).show(captionContainerSurface);
@@ -492,10 +485,6 @@
final SurfaceControl.Builder decorContainerSurfaceBuilder =
createMockSurfaceControlBuilder(decorContainerSurface);
mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
- final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
- final SurfaceControl.Builder captionContainerSurfaceBuilder =
- createMockSurfaceControlBuilder(captionContainerSurface);
- mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
mMockSurfaceControlTransactions.add(t);
@@ -512,10 +501,11 @@
taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo);
- windowDecor.relayout(taskInfo, true /* applyStartTransactionOnDraw */,
- true /* hasGlobalFocus */, Region.obtain());
+ mRelayoutParams.mApplyStartTransactionOnDraw = true;
+ windowDecor.relayout(taskInfo, true /* hasGlobalFocus */, Region.obtain());
- verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT);
+ verify(mMockWindowDecorViewHost).updateView(any(), any(), any(), any(),
+ eq(mMockSurfaceControlStartT));
}
@Test
@@ -918,7 +908,13 @@
/* hasGlobalFocus= */ true,
Region.obtain());
- verify(mMockRootSurfaceControl).applyTransactionOnDraw(mMockSurfaceControlStartT);
+ verify(mMockWindowDecorViewHost)
+ .updateView(
+ eq(mRelayoutResult.mRootView),
+ any(),
+ eq(windowDecor.mTaskInfo.configuration),
+ any(),
+ eq(mMockSurfaceControlStartT));
windowDecor.close();
}
@@ -933,15 +929,11 @@
mRelayoutParams.mAsyncViewHost = true;
mRelayoutResult.mRootView = mMockView;
- windowDecor.relayout(
- windowDecor.mTaskInfo,
- /* hasGlobalFocus= */ true,
- Region.obtain());
- final ArgumentCaptor<Runnable> updateViewHostCaptor =
- ArgumentCaptor.forClass(Runnable.class);
- verify(mMockHandler).post(updateViewHostCaptor.capture());
assertThrows(IllegalArgumentException.class,
- () -> updateViewHostCaptor.getValue().run());
+ () -> windowDecor.relayout(
+ windowDecor.mTaskInfo,
+ /* hasGlobalFocus= */ true,
+ Region.obtain()));
windowDecor.close();
}
@@ -961,13 +953,9 @@
/* hasGlobalFocus= */ true,
Region.obtain());
- final ArgumentCaptor<Runnable> updateViewHostCaptor =
- ArgumentCaptor.forClass(Runnable.class);
- verify(mMockHandler).post(updateViewHostCaptor.capture());
-
- updateViewHostCaptor.getValue().run();
-
- verify(mMockSurfaceControlViewHost).setView(eq(mMockView), any());
+ verify(mMockWindowDecorViewHost)
+ .updateViewAsync(eq(mRelayoutResult.mRootView), any(),
+ eq(windowDecor.mTaskInfo.configuration), any());
windowDecor.close();
}
@@ -1046,13 +1034,14 @@
private TestWindowDecoration createWindowDecoration(ActivityManager.RunningTaskInfo taskInfo) {
return new TestWindowDecoration(mContext, mContext, mMockDisplayController,
- mMockShellTaskOrganizer, mMockHandler, taskInfo, mMockTaskSurface,
+ mMockShellTaskOrganizer, taskInfo, mMockTaskSurface,
new MockObjectSupplier<>(mMockSurfaceControlBuilders,
() -> createMockSurfaceControlBuilder(mock(SurfaceControl.class))),
new MockObjectSupplier<>(mMockSurfaceControlTransactions,
() -> mock(SurfaceControl.Transaction.class)),
() -> mMockWindowContainerTransaction, () -> mMockTaskSurface,
- mMockSurfaceControlViewHostFactory, mDesktopModeEventLogger);
+ mMockSurfaceControlViewHostFactory, mMockWindowDecorViewHostSupplier,
+ mDesktopModeEventLogger);
}
private class MockObjectSupplier<T> implements Supplier<T> {
@@ -1087,7 +1076,6 @@
TestWindowDecoration(Context context, @NonNull Context userContext,
DisplayController displayController,
ShellTaskOrganizer taskOrganizer,
- Handler handler,
ActivityManager.RunningTaskInfo taskInfo,
SurfaceControl taskSurface,
Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
@@ -1095,11 +1083,14 @@
Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
Supplier<SurfaceControl> surfaceControlSupplier,
SurfaceControlViewHostFactory surfaceControlViewHostFactory,
+ @NonNull WindowDecorViewHostSupplier<WindowDecorViewHost>
+ windowDecorViewHostSupplier,
DesktopModeEventLogger desktopModeEventLogger) {
- super(context, userContext, displayController, taskOrganizer, handler, taskInfo,
+ super(context, userContext, displayController, taskOrganizer, taskInfo,
taskSurface, surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
windowContainerTransactionSupplier, surfaceControlSupplier,
- surfaceControlViewHostFactory, desktopModeEventLogger);
+ surfaceControlViewHostFactory, windowDecorViewHostSupplier,
+ desktopModeEventLogger);
}
void relayout(ActivityManager.RunningTaskInfo taskInfo, boolean hasGlobalFocus) {
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index dd5067a..54f172c 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -189,6 +189,7 @@
* the device.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_BUILTIN_SPEAKER
*/
public static final int TYPE_BUILTIN_SPEAKER = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
@@ -196,6 +197,7 @@
* Indicates the route is a headset, which is the combination of a headphones and a microphone.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_WIRED_HEADSET
*/
public static final int TYPE_WIRED_HEADSET = AudioDeviceInfo.TYPE_WIRED_HEADSET;
@@ -203,6 +205,7 @@
* Indicates the route is a pair of wired headphones.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_WIRED_HEADPHONES
*/
public static final int TYPE_WIRED_HEADPHONES = AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
@@ -210,6 +213,7 @@
* Indicates the route is a bluetooth device, such as a bluetooth speaker or headphones.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_BLUETOOTH_A2DP
*/
public static final int TYPE_BLUETOOTH_A2DP = AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
@@ -217,6 +221,7 @@
* Indicates the route is an HDMI connection.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_HDMI
*/
public static final int TYPE_HDMI = AudioDeviceInfo.TYPE_HDMI;
@@ -224,6 +229,7 @@
* Indicates the route is an Audio Return Channel of an HDMI connection.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_HDMI_ARC
*/
@FlaggedApi(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER)
public static final int TYPE_HDMI_ARC = AudioDeviceInfo.TYPE_HDMI_ARC;
@@ -232,24 +238,34 @@
* Indicates the route is an Enhanced Audio Return Channel of an HDMI connection.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_HDMI_EARC
*/
@FlaggedApi(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER)
public static final int TYPE_HDMI_EARC = AudioDeviceInfo.TYPE_HDMI_EARC;
/**
* Indicates the route is a digital line connection (for example S/PDIF).
+ *
+ * @see #getType
+ * @see AudioDeviceInfo#TYPE_LINE_DIGITAL
*/
@FlaggedApi(FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES)
public static final int TYPE_LINE_DIGITAL = AudioDeviceInfo.TYPE_LINE_DIGITAL;
/**
* Indicates the route is an analog line-level connection.
+ *
+ * @see #getType
+ * @see AudioDeviceInfo#TYPE_LINE_ANALOG
*/
@FlaggedApi(FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES)
public static final int TYPE_LINE_ANALOG = AudioDeviceInfo.TYPE_LINE_ANALOG;
/**
* Indicates the route is using the auxiliary line-level connectors.
+ *
+ * @see #getType
+ * @see AudioDeviceInfo#TYPE_AUX_LINE
*/
@FlaggedApi(FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES)
public static final int TYPE_AUX_LINE = AudioDeviceInfo.TYPE_AUX_LINE;
@@ -258,6 +274,7 @@
* Indicates the route is a USB audio device.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_USB_DEVICE
*/
public static final int TYPE_USB_DEVICE = AudioDeviceInfo.TYPE_USB_DEVICE;
@@ -265,6 +282,7 @@
* Indicates the route is a USB audio device in accessory mode.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_USB_ACCESSORY
*/
public static final int TYPE_USB_ACCESSORY = AudioDeviceInfo.TYPE_USB_ACCESSORY;
@@ -272,6 +290,7 @@
* Indicates the route is the audio device associated with a dock.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_DOCK
*/
public static final int TYPE_DOCK = AudioDeviceInfo.TYPE_DOCK;
@@ -279,6 +298,7 @@
* Indicates the route is a USB audio headset.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_USB_HEADSET
*/
public static final int TYPE_USB_HEADSET = AudioDeviceInfo.TYPE_USB_HEADSET;
@@ -286,6 +306,7 @@
* Indicates the route is a hearing aid.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_HEARING_AID
*/
public static final int TYPE_HEARING_AID = AudioDeviceInfo.TYPE_HEARING_AID;
@@ -293,6 +314,7 @@
* Indicates the route is a Bluetooth Low Energy (BLE) HEADSET.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_BLE_HEADSET
*/
public static final int TYPE_BLE_HEADSET = AudioDeviceInfo.TYPE_BLE_HEADSET;
@@ -304,6 +326,7 @@
* to provide a better experience on multichannel contents.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_MULTICHANNEL_GROUP
*/
@FlaggedApi(FLAG_ENABLE_MULTICHANNEL_GROUP_DEVICE)
public static final int TYPE_MULTICHANNEL_SPEAKER_GROUP =
diff --git a/native/android/Android.bp b/native/android/Android.bp
index cd6de5a..129d616 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -73,6 +73,7 @@
"surface_control.cpp",
"surface_texture.cpp",
"system_fonts.cpp",
+ "system_health.cpp",
"trace.cpp",
"thermal.cpp",
],
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 78a7ddb..8dd8830 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -320,6 +320,23 @@
ASystemFontIterator_open; # introduced=29
ASystemFontIterator_close; # introduced=29
ASystemFontIterator_next; # introduced=29
+ ASystemHealth_getCpuHeadroom; # introduced=36
+ ASystemHealth_getGpuHeadroom; # introduced=36
+ ASystemHealth_getCpuHeadroomMinIntervalMillis; # introduced=36
+ ASystemHealth_getGpuHeadroomMinIntervalMillis; # introduced=36
+ ACpuHeadroomParams_create; # introduced=36
+ ACpuHeadroomParams_destroy; # introduced=36
+ ACpuHeadroomParams_setCalculationType; # introduced=36
+ ACpuHeadroomParams_getCalculationType; # introduced=36
+ ACpuHeadroomParams_setCalculationWindowMillis; # introduced=36
+ ACpuHeadroomParams_getCalculationWindowMillis; # introduced=36
+ ACpuHeadroomParams_setTids; # introduced=36
+ AGpuHeadroomParams_create; # introduced=36
+ AGpuHeadroomParams_destroy; # introduced=36
+ AGpuHeadroomParams_setCalculationType; # introduced=36
+ AGpuHeadroomParams_getCalculationType; # introduced=36
+ AGpuHeadroomParams_setCalculationWindowMillis; # introduced=36
+ AGpuHeadroomParams_getCalculationWindowMillis; # introduced=36
AFont_close; # introduced=29
AFont_getFontFilePath; # introduced=29
AFont_getWeight; # introduced=29
diff --git a/native/android/system_health.cpp b/native/android/system_health.cpp
new file mode 100644
index 0000000..f3fa9f6
--- /dev/null
+++ b/native/android/system_health.cpp
@@ -0,0 +1,278 @@
+/*
+ * 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.
+ */
+
+#include <aidl/android/hardware/power/CpuHeadroomParams.h>
+#include <aidl/android/hardware/power/GpuHeadroomParams.h>
+#include <aidl/android/os/CpuHeadroomParamsInternal.h>
+#include <aidl/android/os/GpuHeadroomParamsInternal.h>
+#include <aidl/android/os/IHintManager.h>
+#include <android/binder_manager.h>
+#include <android/system_health.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+
+using namespace android;
+using namespace aidl::android::os;
+namespace hal = aidl::android::hardware::power;
+
+struct ACpuHeadroomParams : public CpuHeadroomParamsInternal {};
+struct AGpuHeadroomParams : public GpuHeadroomParamsInternal {};
+
+const int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50;
+const int CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000;
+const int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN = 50;
+const int GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX = 10000;
+const int CPU_HEADROOM_MAX_TID_COUNT = 5;
+
+struct ASystemHealthManager {
+public:
+ static ASystemHealthManager* getInstance();
+ ASystemHealthManager(std::shared_ptr<IHintManager>& hintManager);
+ ASystemHealthManager() = delete;
+ ~ASystemHealthManager();
+ int getCpuHeadroom(const ACpuHeadroomParams* params, float* outHeadroom);
+ int getGpuHeadroom(const AGpuHeadroomParams* params, float* outHeadroom);
+ int getCpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis);
+ int getGpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis);
+
+private:
+ static ASystemHealthManager* create(std::shared_ptr<IHintManager> hintManager);
+ std::shared_ptr<IHintManager> mHintManager;
+};
+
+ASystemHealthManager* ASystemHealthManager::getInstance() {
+ static std::once_flag creationFlag;
+ static ASystemHealthManager* instance = nullptr;
+ std::call_once(creationFlag, []() { instance = create(nullptr); });
+ return instance;
+}
+
+ASystemHealthManager::ASystemHealthManager(std::shared_ptr<IHintManager>& hintManager)
+ : mHintManager(std::move(hintManager)) {}
+
+ASystemHealthManager::~ASystemHealthManager() {}
+
+ASystemHealthManager* ASystemHealthManager::create(std::shared_ptr<IHintManager> hintManager) {
+ if (!hintManager) {
+ hintManager = IHintManager::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
+ }
+ if (hintManager == nullptr) {
+ ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
+ return nullptr;
+ }
+ return new ASystemHealthManager(hintManager);
+}
+
+ASystemHealthManager* ASystemHealth_acquireManager() {
+ return ASystemHealthManager::getInstance();
+}
+
+int ASystemHealthManager::getCpuHeadroom(const ACpuHeadroomParams* params, float* outHeadroom) {
+ std::optional<hal::CpuHeadroomResult> res;
+ ::ndk::ScopedAStatus ret;
+ CpuHeadroomParamsInternal internalParams;
+ if (!params) {
+ ret = mHintManager->getCpuHeadroom(internalParams, &res);
+ } else {
+ ret = mHintManager->getCpuHeadroom(*params, &res);
+ }
+ if (!ret.isOk()) {
+ LOG_ALWAYS_FATAL_IF(ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT,
+ "Invalid ACpuHeadroomParams: %s", ret.getMessage());
+ ALOGE("ASystemHealth_getCpuHeadroom fails: %s", ret.getMessage());
+ if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ return ENOTSUP;
+ } else if (ret.getExceptionCode() == EX_SECURITY) {
+ return EPERM;
+ }
+ return EPIPE;
+ }
+ *outHeadroom = res->get<hal::CpuHeadroomResult::Tag::globalHeadroom>();
+ return OK;
+}
+
+int ASystemHealthManager::getGpuHeadroom(const AGpuHeadroomParams* params, float* outHeadroom) {
+ std::optional<hal::GpuHeadroomResult> res;
+ ::ndk::ScopedAStatus ret;
+ GpuHeadroomParamsInternal internalParams;
+ if (!params) {
+ ret = mHintManager->getGpuHeadroom(internalParams, &res);
+ } else {
+ ret = mHintManager->getGpuHeadroom(*params, &res);
+ }
+ if (!ret.isOk()) {
+ LOG_ALWAYS_FATAL_IF(ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT,
+ "Invalid AGpuHeadroomParams: %s", ret.getMessage());
+ ALOGE("ASystemHealth_getGpuHeadroom fails: %s", ret.getMessage());
+ if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ return ENOTSUP;
+ }
+ return EPIPE;
+ }
+ *outHeadroom = res->get<hal::GpuHeadroomResult::Tag::globalHeadroom>();
+ return OK;
+}
+
+int ASystemHealthManager::getCpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis) {
+ int64_t minIntervalMillis = 0;
+ ::ndk::ScopedAStatus ret = mHintManager->getCpuHeadroomMinIntervalMillis(&minIntervalMillis);
+ if (!ret.isOk()) {
+ ALOGE("ASystemHealth_getCpuHeadroomMinIntervalMillis fails: %s", ret.getMessage());
+ if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ return ENOTSUP;
+ }
+ return EPIPE;
+ }
+ *outMinIntervalMillis = minIntervalMillis;
+ return OK;
+}
+
+int ASystemHealthManager::getGpuHeadroomMinIntervalMillis(int64_t* outMinIntervalMillis) {
+ int64_t minIntervalMillis = 0;
+ ::ndk::ScopedAStatus ret = mHintManager->getGpuHeadroomMinIntervalMillis(&minIntervalMillis);
+ if (!ret.isOk()) {
+ ALOGE("ASystemHealth_getGpuHeadroomMinIntervalMillis fails: %s", ret.getMessage());
+ if (ret.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ return ENOTSUP;
+ }
+ return EPIPE;
+ }
+ *outMinIntervalMillis = minIntervalMillis;
+ return OK;
+}
+
+int ASystemHealth_getCpuHeadroom(const ACpuHeadroomParams* _Nullable params,
+ float* _Nonnull outHeadroom) {
+ LOG_ALWAYS_FATAL_IF(outHeadroom == nullptr, "%s: outHeadroom should not be null", __FUNCTION__);
+ auto manager = ASystemHealthManager::getInstance();
+ if (manager == nullptr) return ENOTSUP;
+ return manager->getCpuHeadroom(params, outHeadroom);
+}
+
+int ASystemHealth_getGpuHeadroom(const AGpuHeadroomParams* _Nullable params,
+ float* _Nonnull outHeadroom) {
+ LOG_ALWAYS_FATAL_IF(outHeadroom == nullptr, "%s: outHeadroom should not be null", __FUNCTION__);
+ auto manager = ASystemHealthManager::getInstance();
+ if (manager == nullptr) return ENOTSUP;
+ return manager->getGpuHeadroom(params, outHeadroom);
+}
+
+int ASystemHealth_getCpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis) {
+ LOG_ALWAYS_FATAL_IF(outMinIntervalMillis == nullptr,
+ "%s: outMinIntervalMillis should not be null", __FUNCTION__);
+ auto manager = ASystemHealthManager::getInstance();
+ if (manager == nullptr) return ENOTSUP;
+ return manager->getCpuHeadroomMinIntervalMillis(outMinIntervalMillis);
+}
+
+int ASystemHealth_getGpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis) {
+ LOG_ALWAYS_FATAL_IF(outMinIntervalMillis == nullptr,
+ "%s: outMinIntervalMillis should not be null", __FUNCTION__);
+ auto manager = ASystemHealthManager::getInstance();
+ if (manager == nullptr) return ENOTSUP;
+ return manager->getGpuHeadroomMinIntervalMillis(outMinIntervalMillis);
+}
+
+void ACpuHeadroomParams_setCalculationWindowMillis(ACpuHeadroomParams* _Nonnull params,
+ int windowMillis) {
+ LOG_ALWAYS_FATAL_IF(windowMillis < CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN ||
+ windowMillis > CPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX,
+ "%s: windowMillis should be in range [50, 10000] but got %d", __FUNCTION__,
+ windowMillis);
+ params->calculationWindowMillis = windowMillis;
+}
+
+void AGpuHeadroomParams_setCalculationWindowMillis(AGpuHeadroomParams* _Nonnull params,
+ int windowMillis) {
+ LOG_ALWAYS_FATAL_IF(windowMillis < GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MIN ||
+ windowMillis > GPU_HEADROOM_CALCULATION_WINDOW_MILLIS_MAX,
+ "%s: windowMillis should be in range [50, 10000] but got %d", __FUNCTION__,
+ windowMillis);
+ params->calculationWindowMillis = windowMillis;
+}
+
+int ACpuHeadroomParams_getCalculationWindowMillis(ACpuHeadroomParams* _Nonnull params) {
+ return params->calculationWindowMillis;
+}
+
+int AGpuHeadroomParams_getCalculationWindowMillis(AGpuHeadroomParams* _Nonnull params) {
+ return params->calculationWindowMillis;
+}
+
+void ACpuHeadroomParams_setTids(ACpuHeadroomParams* _Nonnull params, const int* _Nonnull tids,
+ int tidsSize) {
+ LOG_ALWAYS_FATAL_IF(tids == nullptr, "%s: tids should not be null", __FUNCTION__);
+ LOG_ALWAYS_FATAL_IF(tidsSize > CPU_HEADROOM_MAX_TID_COUNT, "%s: tids size should not exceed 5",
+ __FUNCTION__);
+ params->tids.resize(tidsSize);
+ params->tids.clear();
+ for (int i = 0; i < tidsSize; ++i) {
+ LOG_ALWAYS_FATAL_IF(tids[i] <= 0, "ACpuHeadroomParams_setTids: Invalid non-positive tid %d",
+ tids[i]);
+ params->tids[i] = tids[i];
+ }
+}
+
+void ACpuHeadroomParams_setCalculationType(ACpuHeadroomParams* _Nonnull params,
+ ACpuHeadroomCalculationType calculationType) {
+ LOG_ALWAYS_FATAL_IF(calculationType < ACpuHeadroomCalculationType::
+ ACPU_HEADROOM_CALCULATION_TYPE_MIN ||
+ calculationType > ACpuHeadroomCalculationType::
+ ACPU_HEADROOM_CALCULATION_TYPE_AVERAGE,
+ "%s: calculationType should be one of ACpuHeadroomCalculationType values "
+ "but got %d",
+ __FUNCTION__, calculationType);
+ params->calculationType = static_cast<hal::CpuHeadroomParams::CalculationType>(calculationType);
+}
+
+ACpuHeadroomCalculationType ACpuHeadroomParams_getCalculationType(
+ ACpuHeadroomParams* _Nonnull params) {
+ return static_cast<ACpuHeadroomCalculationType>(params->calculationType);
+}
+
+void AGpuHeadroomParams_setCalculationType(AGpuHeadroomParams* _Nonnull params,
+ AGpuHeadroomCalculationType calculationType) {
+ LOG_ALWAYS_FATAL_IF(calculationType < AGpuHeadroomCalculationType::
+ AGPU_HEADROOM_CALCULATION_TYPE_MIN ||
+ calculationType > AGpuHeadroomCalculationType::
+ AGPU_HEADROOM_CALCULATION_TYPE_AVERAGE,
+ "%s: calculationType should be one of AGpuHeadroomCalculationType values "
+ "but got %d",
+ __FUNCTION__, calculationType);
+ params->calculationType = static_cast<hal::GpuHeadroomParams::CalculationType>(calculationType);
+}
+
+AGpuHeadroomCalculationType AGpuHeadroomParams_getCalculationType(
+ AGpuHeadroomParams* _Nonnull params) {
+ return static_cast<AGpuHeadroomCalculationType>(params->calculationType);
+}
+
+ACpuHeadroomParams* _Nonnull ACpuHeadroomParams_create() {
+ return new ACpuHeadroomParams();
+}
+
+AGpuHeadroomParams* _Nonnull AGpuHeadroomParams_create() {
+ return new AGpuHeadroomParams();
+}
+
+void ACpuHeadroomParams_destroy(ACpuHeadroomParams* _Nonnull params) {
+ delete params;
+}
+
+void AGpuHeadroomParams_destroy(AGpuHeadroomParams* _Nonnull params) {
+ delete params;
+}
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
index cd03dd7..07b1c9e 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/KeyedObserver.kt
@@ -22,6 +22,7 @@
import com.google.errorprone.annotations.CanIgnoreReturnValue
import java.util.WeakHashMap
import java.util.concurrent.Executor
+import java.util.concurrent.atomic.AtomicInteger
/**
* Callback to be informed of changes in [KeyedObservable] object.
@@ -203,13 +204,71 @@
}
}
- fun hasAnyObserver(): Boolean {
+ open fun hasAnyObserver(): Boolean {
synchronized(observers) { if (observers.isNotEmpty()) return true }
synchronized(keyedObservers) { if (keyedObservers.isNotEmpty()) return true }
return false
}
}
+/** [KeyedDataObservable] that maintains a counter for the observers. */
+abstract class AbstractKeyedDataObservable<K> : KeyedDataObservable<K>() {
+ /**
+ * Counter of observers.
+ *
+ * The value is accurate only when [addObserver] and [removeObserver] are invoked in pairs.
+ */
+ private val counter = AtomicInteger()
+
+ override fun addObserver(observer: KeyedObserver<K?>, executor: Executor) =
+ if (super.addObserver(observer, executor)) {
+ onObserverAdded()
+ true
+ } else {
+ false
+ }
+
+ override fun addObserver(key: K, observer: KeyedObserver<K>, executor: Executor) =
+ if (super.addObserver(key, observer, executor)) {
+ onObserverAdded()
+ true
+ } else {
+ false
+ }
+
+ private fun onObserverAdded() {
+ if (counter.getAndIncrement() == 0) onFirstObserverAdded()
+ }
+
+ /** Callbacks when the first observer is just added. */
+ protected abstract fun onFirstObserverAdded()
+
+ override fun removeObserver(observer: KeyedObserver<K?>) =
+ if (super.removeObserver(observer)) {
+ onObserverRemoved()
+ true
+ } else {
+ false
+ }
+
+ override fun removeObserver(key: K, observer: KeyedObserver<K>) =
+ if (super.removeObserver(key, observer)) {
+ onObserverRemoved()
+ true
+ } else {
+ false
+ }
+
+ private fun onObserverRemoved() {
+ if (counter.decrementAndGet() == 0) onLastObserverRemoved()
+ }
+
+ /** Callbacks when the last observer is just removed. */
+ protected abstract fun onLastObserverRemoved()
+
+ override fun hasAnyObserver() = counter.get() > 0
+}
+
/** [KeyedObservable] with no-op implementations for all interfaces. */
open class NoOpKeyedObservable<K> : KeyedObservable<K> {
diff --git a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt
index 04d4bfe..d6e7a89 100644
--- a/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt
+++ b/packages/SettingsLib/DataStore/src/com/android/settingslib/datastore/SettingsStore.kt
@@ -20,21 +20,10 @@
import android.database.ContentObserver
import android.net.Uri
import android.util.Log
-import java.util.concurrent.Executor
-import java.util.concurrent.atomic.AtomicInteger
/** Base class of the Settings provider data stores. */
abstract class SettingsStore(protected val contentResolver: ContentResolver) :
- KeyedDataObservable<String>(), KeyValueStore {
-
- /**
- * Counter of observers.
- *
- * The value is accurate only when [addObserver] and [removeObserver] are called correctly. When
- * an observer is not removed (and its weak reference is garbage collected), the content
- * observer is not unregistered but this is not a big deal.
- */
- private val counter = AtomicInteger()
+ AbstractKeyedDataObservable<String>(), KeyValueStore {
private val contentObserver =
object : ContentObserver(HandlerExecutor.main) {
@@ -48,49 +37,15 @@
}
}
- override fun addObserver(observer: KeyedObserver<String?>, executor: Executor) =
- if (super.addObserver(observer, executor)) {
- onObserverAdded()
- true
- } else {
- false
- }
+ /** The URI to watch for any key change. */
+ protected abstract val uri: Uri
- override fun addObserver(key: String, observer: KeyedObserver<String>, executor: Executor) =
- if (super.addObserver(key, observer, executor)) {
- onObserverAdded()
- true
- } else {
- false
- }
-
- private fun onObserverAdded() {
- if (counter.getAndIncrement() != 0) return
+ override fun onFirstObserverAdded() {
Log.i(tag, "registerContentObserver")
contentResolver.registerContentObserver(uri, true, contentObserver)
}
- /** The URI to watch for any key change. */
- protected abstract val uri: Uri
-
- override fun removeObserver(observer: KeyedObserver<String?>) =
- if (super.removeObserver(observer)) {
- onObserverRemoved()
- true
- } else {
- false
- }
-
- override fun removeObserver(key: String, observer: KeyedObserver<String>) =
- if (super.removeObserver(key, observer)) {
- onObserverRemoved()
- true
- } else {
- false
- }
-
- private fun onObserverRemoved() {
- if (counter.decrementAndGet() != 0) return
+ override fun onLastObserverRemoved() {
Log.i(tag, "unregisterContentObserver")
contentResolver.unregisterContentObserver(contentObserver)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 2817f55..acc97a9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -43,6 +43,7 @@
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
+import android.app.KeyguardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -182,6 +183,8 @@
@Captor
private ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mFaceAuthenticatorsRegisteredCaptor;
@Captor
+ private ArgumentCaptor<KeyguardManager.KeyguardLockedStateListener> mKeyguardLockedStateCaptor;
+ @Captor
private ArgumentCaptor<BiometricStateListener> mBiometricStateCaptor;
@Captor
private ArgumentCaptor<Integer> mModalityCaptor;
@@ -192,6 +195,8 @@
@Mock
private VibratorHelper mVibratorHelper;
@Mock
+ private KeyguardManager mKeyguardManager;
+ @Mock
private MSDLPlayer mMSDLPlayer;
private TestableContext mContextSpy;
@@ -272,6 +277,9 @@
mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(fpProps);
mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(faceProps);
+ verify(mKeyguardManager).addKeyguardLockedStateListener(any(),
+ mKeyguardLockedStateCaptor.capture());
+
// Ensures that the operations posted on the handler get executed.
waitForIdleSync();
}
@@ -977,6 +985,18 @@
}
@Test
+ public void testCloseDialog_whenDeviceLocks() throws Exception {
+ showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
+
+ mKeyguardLockedStateCaptor.getValue().onKeyguardLockedStateChanged(
+ true /* isKeyguardLocked */);
+
+ verify(mReceiver).onDialogDismissed(
+ eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL),
+ eq(null) /* credentialAttestation */);
+ }
+
+ @Test
public void testShowDialog_whenOwnerNotInForeground() {
PromptInfo promptInfo = createTestPromptInfo();
promptInfo.setAllowBackgroundAuthentication(false);
@@ -1193,7 +1213,7 @@
mWakefulnessLifecycle, mUserManager, mLockPatternUtils, () -> mUdfpsLogger,
() -> mLogContextInteractor, () -> mPromptSelectionInteractor,
() -> mCredentialViewModel, () -> mPromptViewModel, mInteractionJankMonitor,
- mHandler, mBackgroundExecutor, mUdfpsUtils, mVibratorHelper,
+ mHandler, mBackgroundExecutor, mUdfpsUtils, mVibratorHelper, mKeyguardManager,
mLazyViewCapture, mMSDLPlayer);
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt
index 0122028..9edd62a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt
@@ -99,14 +99,14 @@
assertThat(playerModel).isNotNull()
assertThat(playerModel?.titleName).isEqualTo(TITLE)
assertThat(playerModel?.artistName).isEqualTo(ARTIST)
- assertThat(underTest.isNewPlayer(playerModel!!)).isTrue()
+ assertThat(underTest.setPlayer(playerModel!!)).isTrue()
mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData)
assertThat(playerModel).isNotNull()
assertThat(playerModel?.titleName).isEqualTo(TITLE)
assertThat(playerModel?.artistName).isEqualTo(ARTIST)
- assertThat(underTest.isNewPlayer(playerModel!!)).isFalse()
+ assertThat(underTest.setPlayer(playerModel!!)).isFalse()
}
@Test
@@ -120,7 +120,7 @@
assertThat(playerModel).isNotNull()
assertThat(playerModel?.titleName).isEqualTo(TITLE)
assertThat(playerModel?.artistName).isEqualTo(ARTIST)
- assertThat(underTest.isNewPlayer(playerModel!!)).isTrue()
+ assertThat(underTest.setPlayer(playerModel!!)).isTrue()
mediaData = initMediaData(ARTIST_2, TITLE_2)
@@ -129,7 +129,7 @@
assertThat(playerModel).isNotNull()
assertThat(playerModel?.titleName).isEqualTo(TITLE_2)
assertThat(playerModel?.artistName).isEqualTo(ARTIST_2)
- assertThat(underTest.isNewPlayer(playerModel!!)).isTrue()
+ assertThat(underTest.setPlayer(playerModel!!)).isTrue()
}
private fun initMediaData(artist: String, title: String): MediaData {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index f6b6655..b653711 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -27,7 +27,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlertDialog;
-import android.app.KeyguardManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
@@ -320,16 +319,6 @@
mBiometricCallback = new BiometricCallback();
mMSDLPlayer = msdlPlayer;
- // Listener for when device locks from adaptive auth, dismiss prompt
- getContext().getSystemService(KeyguardManager.class).addKeyguardLockedStateListener(
- getContext().getMainExecutor(),
- isKeyguardLocked -> {
- if (isKeyguardLocked) {
- onStartedGoingToSleep();
- }
- }
- );
-
final BiometricModalities biometricModalities = new BiometricModalities(
Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds));
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 4faf6ff..316849d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -27,6 +27,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityTaskManager;
+import android.app.KeyguardManager;
import android.app.TaskStackListener;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -737,6 +738,7 @@
@Background DelayableExecutor bgExecutor,
@NonNull UdfpsUtils udfpsUtils,
@NonNull VibratorHelper vibratorHelper,
+ @NonNull KeyguardManager keyguardManager,
Lazy<ViewCapture> daggerLazyViewCapture,
@NonNull MSDLPlayer msdlPlayer) {
mContext = context;
@@ -768,6 +770,15 @@
mPromptViewModelProvider = promptViewModelProvider;
mCredentialViewModelProvider = credentialViewModelProvider;
+ keyguardManager.addKeyguardLockedStateListener(
+ context.getMainExecutor(),
+ isKeyguardLocked -> {
+ if (isKeyguardLocked) {
+ closeDialog("Device lock");
+ }
+ }
+ );
+
mOrientationListener = new BiometricDisplayListener(
context,
mDisplayManager,
diff --git a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
index 1b044de..0c1bc83 100644
--- a/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
+++ b/packages/SystemUI/src/com/android/systemui/inputdevice/tutorial/ui/composable/ActionTutorialContent.kt
@@ -20,6 +20,7 @@
import androidx.annotation.RawRes
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
+import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -33,8 +34,12 @@
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalConfiguration
@@ -125,6 +130,8 @@
config: TutorialScreenConfig,
modifier: Modifier = Modifier,
) {
+ val focusRequester = remember { FocusRequester() }
+ LaunchedEffect(Unit) { focusRequester.requestFocus() }
val (titleTextId, bodyTextId) =
if (actionState is Finished) {
config.strings.titleSuccessResId to config.strings.bodySuccessResId
@@ -136,6 +143,7 @@
text = stringResource(id = titleTextId),
style = MaterialTheme.typography.displayLarge,
color = config.colors.title,
+ modifier = Modifier.focusRequester(focusRequester).focusable(),
)
Spacer(modifier = Modifier.height(16.dp))
Text(
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
index 341b8d8..1b39d55 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt
@@ -30,14 +30,10 @@
import com.android.systemui.media.controls.util.MediaSmartspaceLogger.Companion.SMARTSPACE_CARD_DISMISS_EVENT
import com.android.systemui.media.controls.util.MediaSmartspaceLogger.Companion.SMARTSPACE_CARD_SEEN_EVENT
import com.android.systemui.media.controls.util.SmallHash
-import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.time.SystemClock
-import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import java.util.Locale
import java.util.TreeMap
import javax.inject.Inject
-import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -49,37 +45,9 @@
constructor(
@Application private val applicationContext: Context,
private val systemClock: SystemClock,
- private val configurationController: ConfigurationController,
private val smartspaceLogger: MediaSmartspaceLogger,
) {
- val onAnyMediaConfigurationChange: Flow<Unit> = conflatedCallbackFlow {
- val callback =
- object : ConfigurationController.ConfigurationListener {
- override fun onDensityOrFontScaleChanged() {
- trySend(Unit)
- }
-
- override fun onThemeChanged() {
- trySend(Unit)
- }
-
- override fun onUiModeChanged() {
- trySend(Unit)
- }
-
- override fun onLocaleListChanged() {
- if (locale != applicationContext.resources.configuration.locales.get(0)) {
- locale = applicationContext.resources.configuration.locales.get(0)
- trySend(Unit)
- }
- }
- }
- configurationController.addCallback(callback)
- trySend(Unit)
- awaitClose { configurationController.removeCallback(callback) }
- }
-
/** Instance id of media control that recommendations card reactivated. */
private val _reactivatedId: MutableStateFlow<InstanceId?> = MutableStateFlow(null)
val reactivatedId: StateFlow<InstanceId?> = _reactivatedId.asStateFlow()
@@ -190,7 +158,7 @@
fun addMediaDataLoadingState(
mediaDataLoadingModel: MediaDataLoadingModel,
- isUpdate: Boolean = true
+ isUpdate: Boolean = true,
) {
val sortedMap = TreeMap<MediaSortKeyModel, MediaCommonModel>(comparator)
sortedMap.putAll(
@@ -395,7 +363,7 @@
logSmarspaceRecommendationCardUserEvent(
SMARTSPACE_CARD_SEEN_EVENT,
surface,
- visibleIndex
+ visibleIndex,
)
}
}
@@ -409,7 +377,7 @@
interactedSubCardRank: Int = 0,
interactedSubCardCardinality: Int = 0,
instanceId: InstanceId? = null,
- isRec: Boolean = false
+ isRec: Boolean = false,
) {
_currentMedia.value.forEachIndexed { index, mediaCommonModel ->
when (mediaCommonModel) {
@@ -423,7 +391,7 @@
surface,
mediaCommonModel.mediaLoadedModel.isSsReactivated,
interactedSubCardRank,
- interactedSubCardCardinality
+ interactedSubCardCardinality,
)
}
return
@@ -437,7 +405,7 @@
surface,
index,
interactedSubCardRank,
- interactedSubCardCardinality
+ interactedSubCardCardinality,
)
}
return
@@ -459,14 +427,14 @@
SMARTSPACE_CARD_DISMISS_EVENT,
surface,
mediaCommonModel.mediaLoadedModel.isSsReactivated,
- isSwipeToDismiss = true
+ isSwipeToDismiss = true,
)
is MediaCommonModel.MediaRecommendations ->
logSmarspaceRecommendationCardUserEvent(
SMARTSPACE_CARD_DISMISS_EVENT,
surface,
index,
- isSwipeToDismiss = true
+ isSwipeToDismiss = true,
)
}
}
@@ -513,7 +481,7 @@
isReactivated: Boolean,
interactedSubCardRank: Int = 0,
interactedSubCardCardinality: Int = 0,
- isSwipeToDismiss: Boolean = false
+ isSwipeToDismiss: Boolean = false,
) {
_selectedUserEntries.value[instanceId]?.let {
smartspaceLogger.logSmartspaceCardUIEvent(
@@ -537,7 +505,7 @@
index: Int,
interactedSubCardRank: Int = 0,
interactedSubCardCardinality: Int = 0,
- isSwipeToDismiss: Boolean = false
+ isSwipeToDismiss: Boolean = false,
) {
smartspaceLogger.logSmartspaceCardUIEvent(
eventId,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
index 1f339dd..09aa85b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt
@@ -68,8 +68,6 @@
.map { entries -> entries[instanceId]?.let { toMediaControlModel(it) } }
.distinctUntilChanged()
- val onAnyMediaConfigurationChange: Flow<Unit> = repository.onAnyMediaConfigurationChange
-
fun removeMediaControl(
token: MediaSession.Token?,
instanceId: InstanceId,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaRecommendationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaRecommendationsInteractor.kt
index c3a36b2..48ed391 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaRecommendationsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaRecommendationsInteractor.kt
@@ -66,14 +66,12 @@
.distinctUntilChanged()
.stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
- val onAnyMediaConfigurationChange: Flow<Unit> = repository.onAnyMediaConfigurationChange
-
fun removeMediaRecommendations(
key: String,
dismissIntent: Intent?,
delayMs: Long,
eventId: Int,
- location: Int
+ location: Int,
) {
logSmartspaceCardUserEvent(eventId, location)
mediaDataProcessor.dismissSmartspaceRecommendation(key, delayMs)
@@ -101,7 +99,7 @@
eventId: Int,
location: Int,
interactedSubCardRank: Int,
- interactedSubCardCardinality: Int
+ interactedSubCardCardinality: Int,
) {
if (interactedSubCardRank == -1) {
logSmartspaceCardUserEvent(eventId, MediaSmartspaceLogger.getSurface(location))
@@ -111,7 +109,7 @@
MediaSmartspaceLogger.getSurface(location),
interactedSubCardRank = interactedSubCardRank,
interactedSubCardCardinality = interactedSubCardCardinality,
- isRec = true
+ isRec = true,
)
}
if (shouldActivityOpenInForeground(intent)) {
@@ -121,7 +119,7 @@
0 /* delay */,
expandable.activityTransitionController(
InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER
- )
+ ),
)
} else {
// Otherwise, open the activity in background directly.
@@ -133,7 +131,7 @@
repository.logSmartspaceCardUserEvent(
eventId,
MediaSmartspaceLogger.getSurface(location),
- isRec = true
+ isRec = true,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt
index a6e1582..910d3a8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt
@@ -34,6 +34,7 @@
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.settingslib.widget.AdaptiveIcon
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon
@@ -64,7 +65,6 @@
import com.android.systemui.surfaceeffects.ripple.RippleShader
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.collectLatest
-import com.android.app.tracing.coroutines.launchTraced as launch
import kotlinx.coroutines.withContext
private const val TAG = "MediaControlViewBinder"
@@ -85,7 +85,7 @@
launch {
viewModel.player.collectLatest { player ->
player?.let {
- if (viewModel.isNewPlayer(it)) {
+ if (viewModel.setPlayer(it)) {
bindMediaCard(
viewHolder,
viewController,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
index 43c2011..f0f8a95 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt
@@ -37,6 +37,7 @@
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.DiffUtil
+import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.app.tracing.traceSection
import com.android.internal.logging.InstanceId
import com.android.keyguard.KeyguardUpdateMonitor
@@ -115,7 +116,6 @@
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
-import com.android.app.tracing.coroutines.launchTraced as launch
import kotlinx.coroutines.withContext
private const val TAG = "MediaCarouselController"
@@ -752,7 +752,11 @@
}
}
- private fun onAdded(commonViewModel: MediaCommonViewModel, position: Int) {
+ private fun onAdded(
+ commonViewModel: MediaCommonViewModel,
+ position: Int,
+ configChanged: Boolean = false,
+ ) {
val viewController = mediaViewControllerFactory.get()
viewController.sizeChangedListener = this::updateCarouselDimensions
val lp =
@@ -763,12 +767,13 @@
when (commonViewModel) {
is MediaCommonViewModel.MediaControl -> {
val viewHolder = MediaViewHolder.create(LayoutInflater.from(context), mediaContent)
- if (SceneContainerFlag.isEnabled) {
- viewController.widthInSceneContainerPx = widthInSceneContainerPx
- viewController.heightInSceneContainerPx = heightInSceneContainerPx
- }
+ viewController.widthInSceneContainerPx = widthInSceneContainerPx
+ viewController.heightInSceneContainerPx = heightInSceneContainerPx
viewController.attachPlayer(viewHolder)
viewController.mediaViewHolder?.player?.layoutParams = lp
+ if (configChanged) {
+ commonViewModel.controlViewModel.onMediaConfigChanged()
+ }
MediaControlViewBinder.bind(
viewHolder,
commonViewModel.controlViewModel,
@@ -1271,23 +1276,14 @@
ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
if (recreateMedia) {
mediaContent.removeAllViews()
- commonViewModels.forEach { viewModel ->
+ commonViewModels.forEachIndexed { index, viewModel ->
when (viewModel) {
- is MediaCommonViewModel.MediaControl -> {
- controllerById[viewModel.instanceId.toString()]?.let {
- it.widthInSceneContainerPx = widthInSceneContainerPx
- it.heightInSceneContainerPx = heightInSceneContainerPx
- mediaContent.addView(it.mediaViewHolder?.player)
- }
- }
- is MediaCommonViewModel.MediaRecommendations -> {
- controllerById[viewModel.key]?.let {
- it.widthInSceneContainerPx = widthInSceneContainerPx
- it.heightInSceneContainerPx = heightInSceneContainerPx
- mediaContent.addView(it.recommendationViewHolder?.recommendations)
- }
- }
+ is MediaCommonViewModel.MediaControl ->
+ controllerById[viewModel.instanceId.toString()]?.onDestroy()
+ is MediaCommonViewModel.MediaRecommendations ->
+ controllerById[viewModel.key]?.onDestroy()
}
+ onAdded(viewModel, index, configChanged = true)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
index 4173d2a..4e97f20 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt
@@ -41,10 +41,8 @@
import com.android.systemui.res.R
import java.util.concurrent.Executor
import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
@@ -56,15 +54,9 @@
private val interactor: MediaControlInteractor,
private val logger: MediaUiEventLogger,
) {
-
- @OptIn(ExperimentalCoroutinesApi::class)
val player: Flow<MediaPlayerViewModel?> =
- interactor.onAnyMediaConfigurationChange
- .flatMapLatest {
- interactor.mediaControl.map { mediaControl ->
- mediaControl?.let { toViewModel(it) }
- }
- }
+ interactor.mediaControl
+ .map { mediaControl -> mediaControl?.let { toViewModel(it) } }
.distinctUntilChanged { old, new ->
(new == null && old == null) || new?.contentEquals(old) ?: false
}
@@ -74,14 +66,21 @@
private var isAnyButtonClicked = false
@MediaLocation private var location = MediaHierarchyManager.LOCATION_UNKNOWN
private var playerViewModel: MediaPlayerViewModel? = null
+ private var allowPlayerUpdate: Boolean = false
- fun isNewPlayer(viewModel: MediaPlayerViewModel): Boolean {
- val contentEquals = playerViewModel?.contentEquals(viewModel) ?: false
- return (!contentEquals).also { playerViewModel = viewModel }
+ fun setPlayer(viewModel: MediaPlayerViewModel): Boolean {
+ val tempViewModel = playerViewModel
+ playerViewModel = viewModel
+ return allowPlayerUpdate || !(tempViewModel?.contentEquals(viewModel) ?: false)
+ }
+
+ fun onMediaConfigChanged() {
+ allowPlayerUpdate = true
}
fun onMediaControlIsBound(artistName: CharSequence, titleName: CharSequence) {
interactor.logMediaControlIsBound(artistName, titleName)
+ allowPlayerUpdate = false
}
private fun onDismissMediaData(
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt
index 6bc6b10a..88cfbaf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt
@@ -41,10 +41,8 @@
import com.android.systemui.res.R
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
@@ -59,12 +57,9 @@
private val logger: MediaUiEventLogger,
) {
- @OptIn(ExperimentalCoroutinesApi::class)
val mediaRecsCard: Flow<MediaRecsCardViewModel?> =
- interactor.onAnyMediaConfigurationChange
- .flatMapLatest {
- interactor.recommendations.map { recsCard -> toRecsViewModel(recsCard) }
- }
+ interactor.recommendations
+ .map { recsCard -> toRecsViewModel(recsCard) }
.distinctUntilChanged()
.flowOn(backgroundDispatcher)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryKosmos.kt
index 7a04aa2..7964c11 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryKosmos.kt
@@ -19,7 +19,6 @@
import android.content.applicationContext
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.media.controls.util.mediaSmartspaceLogger
-import com.android.systemui.statusbar.policy.configurationController
import com.android.systemui.util.time.systemClock
val Kosmos.mediaFilterRepository by
@@ -27,7 +26,6 @@
MediaFilterRepository(
applicationContext = applicationContext,
systemClock = systemClock,
- configurationController = configurationController,
smartspaceLogger = mediaSmartspaceLogger,
)
}
diff --git a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
index f5360eb..6b28047 100644
--- a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
+++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
@@ -213,7 +213,8 @@
}
private int getShareEventType(IntentFilter intentFilter) {
- String mimeType = intentFilter != null ? intentFilter.getDataType(0) : null;
+ String mimeType = (intentFilter != null && intentFilter.countDataTypes() > 0)
+ ? intentFilter.getDataType(0) : null;
return getDataManager().mimeTypeToShareEventType(mimeType);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerTest.java
index d58e772..835705d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/fudger/LocationFudgerTest.java
@@ -188,8 +188,8 @@
}
@Test
- public void testDensityBasedCoarsening_ifFeatureIsEnabledButNotDefault_cacheIsNotUsed() {
- mSetFlagsRule.disableFlags(Flags.FLAG_DENSITY_BASED_COARSE_LOCATIONS);
+ public void testDensityBasedCoarsening_ifFeatureIsEnabledButNoDefaultValue_cacheIsNotUsed() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_DENSITY_BASED_COARSE_LOCATIONS);
LocationFudgerCache cache = mock(LocationFudgerCache.class);
doReturn(false).when(cache).hasDefaultValue();
diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
index 27486b7..71a05f3 100644
--- a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
@@ -286,6 +286,25 @@
}
@Test
+ public void testPredictTargets_emptyIntentFilter() {
+ Bundle bundle = new Bundle();
+ IntentFilter filter = new IntentFilter();
+ bundle.putObject(ChooserActivity.APP_PREDICTION_INTENT_FILTER_KEY, filter);
+ AppPredictionContext predictionContext = new AppPredictionContext.Builder(mContext)
+ .setUiSurface(UI_SURFACE_SHARE)
+ .setPredictedTargetCount(NUM_PREDICTED_TARGETS)
+ .setExtras(bundle)
+ .build();
+ mPredictor = new ShareTargetPredictor(
+ predictionContext, mUpdatePredictionsMethod, mDataManager, USER_ID, mContext);
+
+ mPredictor.predictTargets();
+
+ verify(mUpdatePredictionsMethod).accept(mAppTargetCaptor.capture());
+ assertThat(mAppTargetCaptor.getValue()).isEmpty();
+ }
+
+ @Test
public void testPredictTargets_noSharingHistoryRankedByShortcutRank() {
mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc1", 3));
mShareShortcuts.add(buildShareShortcut(PACKAGE_1, CLASS_1, "sc2", 2));