Merge "Add scrolling_from_letterbox flag" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index af3981c..7a1add3 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -242,6 +242,12 @@
aconfig_declarations: "com.android.text.flags-aconfig",
}
+rust_aconfig_library {
+ name: "libandroid_text_flags_rust",
+ crate_name: "android_text_flags",
+ aconfig_declarations: "com.android.text.flags-aconfig",
+}
+
// Location
aconfig_declarations {
name: "android.location.flags-aconfig",
@@ -372,6 +378,7 @@
min_sdk_version: "30",
apex_available: [
"//apex_available:platform",
+ "com.android.btservices",
"com.android.mediaprovider",
"com.android.permission",
],
@@ -412,17 +419,6 @@
cc_aconfig_library {
name: "android.companion.virtualdevice.flags-aconfig-cc",
aconfig_declarations: "android.companion.virtualdevice.flags-aconfig",
-}
-
-cc_aconfig_library {
- name: "android.companion.virtualdevice.flags-aconfig-cc-host",
- aconfig_declarations: "android.companion.virtualdevice.flags-aconfig",
- host_supported: true,
-}
-
-cc_aconfig_library {
- name: "android.companion.virtualdevice.flags-aconfig-cc-test",
- aconfig_declarations: "android.companion.virtualdevice.flags-aconfig",
host_supported: true,
mode: "test",
}
diff --git a/Android.bp b/Android.bp
index f0aa62c..eabd9c7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -417,7 +417,6 @@
"modules-utils-fastxmlserializer",
"modules-utils-preconditions",
"modules-utils-statemachine",
- "modules-utils-synchronous-result-receiver",
"modules-utils-os",
"modules-utils-uieventlogger-interface",
"framework-permission-aidl-java",
diff --git a/apct-tests/perftests/multiuser/Android.bp b/apct-tests/perftests/multiuser/Android.bp
index 1653edc..856dba3 100644
--- a/apct-tests/perftests/multiuser/Android.bp
+++ b/apct-tests/perftests/multiuser/Android.bp
@@ -38,3 +38,10 @@
],
certificate: "platform",
}
+
+filegroup {
+ name: "multi_user_trace_config",
+ srcs: [
+ "trace_configs/trace_config_multi_user.textproto",
+ ],
+}
diff --git a/api/Android.bp b/api/Android.bp
index 89a0c18..d931df1 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -62,40 +62,8 @@
metalava_cmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED "
metalava_cmd += " --quiet "
-soong_config_module_type {
- name: "enable_crashrecovery_module",
- module_type: "combined_apis_defaults",
- config_namespace: "ANDROID",
- bool_variables: ["release_crashrecovery_module"],
- properties: [
- "bootclasspath",
- "system_server_classpath",
- ],
-}
-
-soong_config_bool_variable {
- name: "release_crashrecovery_module",
-}
-
-enable_crashrecovery_module {
- name: "crashrecovery_module_defaults",
- soong_config_variables: {
- release_crashrecovery_module: {
- bootclasspath: [
- "framework-crashrecovery",
- ],
- system_server_classpath: [
- "service-crashrecovery",
- ],
- },
- },
-}
-
combined_apis {
name: "frameworks-base-api",
- defaults: [
- "crashrecovery_module_defaults",
- ],
bootclasspath: [
"android.net.ipsec.ike",
"art.module.public.api",
@@ -128,7 +96,12 @@
"framework-virtualization",
"framework-wifi",
"i18n.module.public.api",
- ],
+ ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
+ "true": [
+ "framework-crashrecovery",
+ ],
+ default: [],
+ }),
system_server_classpath: [
"service-art",
"service-configinfrastructure",
@@ -137,7 +110,12 @@
"service-permission",
"service-rkp",
"service-sdksandbox",
- ],
+ ] + select(soong_config_variable("ANDROID", "release_crashrecovery_module"), {
+ "true": [
+ "service-crashrecovery",
+ ],
+ default: [],
+ }),
}
genrule {
diff --git a/api/api.go b/api/api.go
index f0d1f42..b6b1a7e 100644
--- a/api/api.go
+++ b/api/api.go
@@ -63,7 +63,6 @@
type CombinedApis struct {
android.ModuleBase
- android.DefaultableModuleBase
properties CombinedApisProperties
}
@@ -74,7 +73,6 @@
func registerBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("combined_apis", combinedApisModuleFactory)
- ctx.RegisterModuleType("combined_apis_defaults", CombinedApisModuleDefaultsFactory)
}
var PrepareForCombinedApisTest = android.FixtureRegisterWithContext(registerBuildComponents)
@@ -576,7 +574,6 @@
module := &CombinedApis{}
module.AddProperties(&module.properties)
android.InitAndroidModule(module)
- android.InitDefaultableModule(module)
android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.createInternalModules(ctx) })
return module
}
@@ -613,16 +610,3 @@
}
return s2
}
-
-// Defaults
-type CombinedApisModuleDefaults struct {
- android.ModuleBase
- android.DefaultsModuleBase
-}
-
-func CombinedApisModuleDefaultsFactory() android.Module {
- module := &CombinedApisModuleDefaults{}
- module.AddProperties(&CombinedApisProperties{})
- android.InitDefaultsModule(module)
- return module
-}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 36b1eab..6df971a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -2105,8 +2105,7 @@
@Override
public void scheduleTaskFragmentTransaction(@NonNull ITaskFragmentOrganizer organizer,
@NonNull TaskFragmentTransaction transaction) throws RemoteException {
- // TODO(b/260873529): ITaskFragmentOrganizer can be cleanup to be a IBinder token
- // after flag removal.
+ // TODO(b/352665082): ITaskFragmentOrganizer can be cleanup to be a IBinder token
organizer.onTransactionReady(transaction);
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index a49ee7d..0c34c6f 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -110,92 +110,6 @@
void shutdown();
/**
- ** TETHERING RELATED
- **/
-
- /**
- * Returns true if IP forwarding is enabled
- */
- @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
- publicAlternatives = "Use {@code android.net.INetd#ipfwdEnabled}")
- boolean getIpForwardingEnabled();
-
- /**
- * Enables/Disables IP Forwarding
- */
- @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
- publicAlternatives = "Avoid using this directly. Instead, enable tethering with "
- + "{@code android.net.TetheringManager#startTethering}. See also "
- + "{@code INetd#ipfwdEnableForwarding(String)}.")
- void setIpForwardingEnabled(boolean enabled);
-
- /**
- * Start tethering services with the specified dhcp server range
- * arg is a set of start end pairs defining the ranges.
- */
- @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
- publicAlternatives = "{@code android.net.TetheringManager#startTethering}")
- void startTethering(in String[] dhcpRanges);
-
- /**
- * Stop currently running tethering services
- */
- @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
- publicAlternatives = "{@code android.net.TetheringManager#stopTethering(int)}")
- void stopTethering();
-
- /**
- * Returns true if tethering services are started
- */
- @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
- publicAlternatives = "Generally track your own tethering requests. "
- + "See also {@code android.net.INetd#tetherIsEnabled()}")
- boolean isTetheringStarted();
-
- /**
- * Tethers the specified interface
- */
- @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
- publicAlternatives = "Avoid using this directly. Instead, enable tethering with "
- + "{@code android.net.TetheringManager#startTethering}. See also "
- + "{@code com.android.net.module.util.NetdUtils#tetherInterface}.")
- void tetherInterface(String iface);
-
- /**
- * Untethers the specified interface
- */
- @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
- publicAlternatives = "Avoid using this directly. Instead, disable "
- + "tethering with {@code android.net.TetheringManager#stopTethering(int)}. "
- + "See also {@code NetdUtils#untetherInterface}.")
- void untetherInterface(String iface);
-
- /**
- * Returns a list of currently tethered interfaces
- */
- @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
- publicAlternatives = "{@code android.net.TetheringManager#getTetheredIfaces()}")
- String[] listTetheredInterfaces();
-
- /**
- * Enables Network Address Translation between two interfaces.
- * The address and netmask of the external interface is used for
- * the NAT'ed network.
- */
- @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
- publicAlternatives = "Avoid using this directly. Instead, enable tethering with "
- + "{@code android.net.TetheringManager#startTethering}.")
- void enableNat(String internalInterface, String externalInterface);
-
- /**
- * Disables Network Address Translation between two interfaces.
- */
- @UnsupportedAppUsage(maxTargetSdk = 34, trackingBug = 170729553,
- publicAlternatives = "Avoid using this directly. Instead, disable tethering with "
- + "{@code android.net.TetheringManager#stopTethering(int)}.")
- void disableNat(String internalInterface, String externalInterface);
-
- /**
** DATA USAGE RELATED
**/
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 0be2d3e3..e95c6a4 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -277,7 +277,7 @@
if (service != null) {
return service;
} else {
- return Binder.allowBlocking(getIServiceManager().checkService(name));
+ return Binder.allowBlocking(getIServiceManager().checkService(name).getBinder());
}
} catch (RemoteException e) {
Log.e(TAG, "error in checkService", e);
@@ -425,7 +425,7 @@
private static IBinder rawGetService(String name) throws RemoteException {
final long start = sStatLogger.getTime();
- final IBinder binder = getIServiceManager().getService(name);
+ final IBinder binder = getIServiceManager().getService(name).getBinder();
final int time = (int) sStatLogger.logDurationStat(Stats.GET_SERVICE, start);
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 7b91dd5..6c9a5c7 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -58,12 +58,12 @@
}
@UnsupportedAppUsage
- public IBinder getService(String name) throws RemoteException {
+ public Service getService(String name) throws RemoteException {
// Same as checkService (old versions of servicemanager had both methods).
- return mServiceManager.checkService(name);
+ return checkService(name);
}
- public IBinder checkService(String name) throws RemoteException {
+ public Service checkService(String name) throws RemoteException {
return mServiceManager.checkService(name);
}
diff --git a/core/java/android/text/ClientFlags.java b/core/java/android/text/ClientFlags.java
index 5d84d17..b07534f 100644
--- a/core/java/android/text/ClientFlags.java
+++ b/core/java/android/text/ClientFlags.java
@@ -68,4 +68,11 @@
public static boolean fixMisalignedContextMenu() {
return TextFlags.isFeatureEnabled(Flags.FLAG_FIX_MISALIGNED_CONTEXT_MENU);
}
+
+ /**
+ * @see Flags#clearFontVariationSettings()
+ */
+ public static boolean clearFontVariationSettings() {
+ return TextFlags.isFeatureEnabled(Flags.FLAG_CLEAR_FONT_VARIATION_SETTINGS);
+ }
}
diff --git a/core/java/android/text/TextFlags.java b/core/java/android/text/TextFlags.java
index 9e02460..4dca284 100644
--- a/core/java/android/text/TextFlags.java
+++ b/core/java/android/text/TextFlags.java
@@ -61,6 +61,7 @@
Flags.FLAG_FIX_LINE_HEIGHT_FOR_LOCALE,
Flags.FLAG_ICU_BIDI_MIGRATION,
Flags.FLAG_FIX_MISALIGNED_CONTEXT_MENU,
+ Flags.FLAG_CLEAR_FONT_VARIATION_SETTINGS,
};
/**
@@ -75,6 +76,7 @@
Flags.fixLineHeightForLocale(),
Flags.icuBidiMigration(),
Flags.fixMisalignedContextMenu(),
+ Flags.clearFontVariationSettings(),
};
/**
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index 8836c8a..02c63db 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -220,3 +220,23 @@
is_fixed_read_only: true
bug: "346915432"
}
+
+flag {
+ name: "clear_font_variation_settings"
+ namespace: "text"
+ description: "The font variation settings must be cleared when the new Typeface is set"
+ bug: "353609778"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "portuguese_hyphenator"
+ namespace: "text"
+ description: "Portuguese taiored hyphenator"
+ bug: "344656282"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index fedbe4a..42d66ce 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -366,13 +366,8 @@
Log.e(TAG, "Received invalid input event");
return;
}
- try {
- vri.processingBackKey(true);
- vri.enqueueInputEvent(keyEvent, null /* receiver */, 0 /* flags */,
- true /* processImmediately */);
- } finally {
- vri.processingBackKey(false);
- }
+ vri.enqueueInputEvent(keyEvent, null /* receiver */, 0 /* flags */,
+ true /* processImmediately */);
});
}
};
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3a1d833..2f204f9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -727,8 +727,6 @@
boolean mUpcomingWindowFocus;
@GuardedBy("this")
boolean mUpcomingInTouchMode;
- // While set, allow this VRI to handle back key without drop it.
- private boolean mProcessingBackKey;
/**
* Compatibility {@link OnBackInvokedCallback} for windowless window, to forward the back
* key event host app.
@@ -7269,7 +7267,7 @@
// Find a reason for dropping or canceling the event.
final String reason;
// The embedded window is focused, allow this VRI to handle back key.
- if (!mAttachInfo.mHasWindowFocus && !(mProcessingBackKey && isBack(q.mEvent))
+ if (!mAttachInfo.mHasWindowFocus && !isBack(q.mEvent)
&& !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
&& !isAutofillUiShowing()) {
// This is a non-pointer event and the window doesn't currently have input focus
@@ -11218,11 +11216,6 @@
mHandler.obtainMessage(MSG_REQUEST_SCROLL_CAPTURE, listener).sendToTarget();
}
- // Make this VRI able to process back key without drop it.
- void processingBackKey(boolean processing) {
- mProcessingBackKey = processing;
- }
-
/**
* Collect and include any ScrollCaptureCallback instances registered with the window.
*
@@ -12554,15 +12547,8 @@
* @return whether the event was handled (i.e. onKeyPreIme consumed it if preImeOnly=true)
*/
public boolean injectBackKeyEvents(boolean preImeOnly) {
- boolean consumed;
- try {
- processingBackKey(true);
- sendBackKeyEvent(KeyEvent.ACTION_DOWN, preImeOnly);
- consumed = sendBackKeyEvent(KeyEvent.ACTION_UP, preImeOnly);
- } finally {
- processingBackKey(false);
- }
- return consumed;
+ sendBackKeyEvent(KeyEvent.ACTION_DOWN, preImeOnly);
+ return sendBackKeyEvent(KeyEvent.ACTION_UP, preImeOnly);
}
private boolean sendBackKeyEvent(int action, boolean preImeOnly) {
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index 5b1c7d5..0ab51e4 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -563,7 +563,7 @@
return DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_AUTOFILL,
DEVICE_CONFIG_ENABLE_RELAYOUT,
- true);
+ false);
}
/** @hide */
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index ae9d757..13d465f 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -3,16 +3,6 @@
# Project link: https://gantry.corp.google.com/projects/android_platform_windowing_sdk/changes
-# Using a fixed read only flag because there are ClientTransaction scheduling before
-# WindowManagerService creation.
-flag {
- namespace: "windowing_sdk"
- name: "bundle_client_transaction_flag"
- description: "To bundle multiple ClientTransactionItems into one ClientTransaction"
- bug: "260873529"
- is_fixed_read_only: true
-}
-
flag {
namespace: "windowing_sdk"
name: "activity_embedding_overlay_presentation_flag"
diff --git a/core/java/com/android/internal/os/PowerStats.java b/core/java/com/android/internal/os/PowerStats.java
index 24971f5..488e06f 100644
--- a/core/java/com/android/internal/os/PowerStats.java
+++ b/core/java/com/android/internal/os/PowerStats.java
@@ -580,10 +580,15 @@
}
PowerStatsFormatter uidStatsFormatter = descriptor.getUidStatsFormatter();
for (int i = 0; i < uidStats.size(); i++) {
+ String formattedStats = uidStatsFormatter.format(uidStats.valueAt(i));
+ if (formattedStats.isBlank()) {
+ continue;
+ }
+
pw.print("UID ");
pw.print(UserHandle.formatUid(uidStats.keyAt(i)));
pw.print(": ");
- pw.print(uidStatsFormatter.format(uidStats.valueAt(i)));
+ pw.print(formattedStats);
pw.println();
}
pw.decreaseIndent();
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index df95a91..b83931f 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -35,6 +35,7 @@
import android.graphics.fonts.FontVariationAxis;
import android.os.Build;
import android.os.LocaleList;
+import android.text.ClientFlags;
import android.text.GraphicsOperations;
import android.text.SpannableString;
import android.text.SpannedString;
@@ -1540,8 +1541,21 @@
* @return typeface
*/
public Typeface setTypeface(Typeface typeface) {
+ return setTypefaceInternal(typeface, true);
+ }
+
+ private Typeface setTypefaceInternal(Typeface typeface, boolean clearFontVariationSettings) {
final long typefaceNative = typeface == null ? 0 : typeface.native_instance;
nSetTypeface(mNativePaint, typefaceNative);
+
+ if (ClientFlags.clearFontVariationSettings()) {
+ if (clearFontVariationSettings && !Objects.equals(mTypeface, typeface)) {
+ // We cannot call setFontVariationSetting with empty string or null because it calls
+ // setTypeface method. To avoid recursive setTypeface call, manually resetting
+ // mFontVariationSettings.
+ mFontVariationSettings = null;
+ }
+ }
mTypeface = typeface;
return typeface;
}
@@ -2037,6 +2051,14 @@
* </li>
* </ul>
*
+ * Note: This method replaces the Typeface previously set to this instance.
+ * Until API {@link Build.VERSION_CODES.VANILLA_ICE_CREAM}, any caller of
+ * {@link #setTypeface(Typeface)} should call this method with empty settings, then call
+ * {@link #setTypeface(Typeface)}, then call this method with preferred variation settings.
+ * The device API more than {@link Build.VERSION_CODES.VANILLA_ICE_CREAM}, the
+ * {@link #setTypeface(Typeface)} method clears font variation settings. So caller of
+ * {@link #setTypeface(Typeface)} should call this method again for applying variation settings.
+ *
* @param fontVariationSettings font variation settings. You can pass null or empty string as
* no variation settings.
*
@@ -2059,8 +2081,8 @@
if (settings == null || settings.length() == 0) {
mFontVariationSettings = null;
- setTypeface(Typeface.createFromTypefaceWithVariation(mTypeface,
- Collections.emptyList()));
+ setTypefaceInternal(Typeface.createFromTypefaceWithVariation(mTypeface,
+ Collections.emptyList()), false);
return true;
}
@@ -2078,7 +2100,8 @@
return false;
}
mFontVariationSettings = settings;
- setTypeface(Typeface.createFromTypefaceWithVariation(targetTypeface, filteredAxes));
+ setTypefaceInternal(Typeface.createFromTypefaceWithVariation(targetTypeface, filteredAxes),
+ false);
return true;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index ecf4720..7f11fea 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -39,6 +39,8 @@
import androidx.window.extensions.layout.WindowLayoutComponent;
import androidx.window.extensions.layout.WindowLayoutComponentImpl;
+import com.android.window.flags.Flags;
+
import java.util.Objects;
@@ -55,11 +57,9 @@
*/
private static final int NO_LEVEL_OVERRIDE = -1;
- /**
- * The min version of the WM Extensions that must be supported in the current platform version.
- */
- @VisibleForTesting
- static final int EXTENSIONS_VERSION_CURRENT_PLATFORM = 6;
+ private static final int EXTENSIONS_VERSION_V7 = 7;
+
+ private static final int EXTENSIONS_VERSION_V6 = 6;
private final Object mLock = new Object();
private volatile DeviceStateManagerFoldingFeatureProducer mFoldingFeatureProducer;
@@ -67,7 +67,6 @@
private volatile SplitController mSplitController;
private volatile WindowAreaComponent mWindowAreaComponent;
- private final int mVersion = EXTENSIONS_VERSION_CURRENT_PLATFORM;
private final boolean mIsActivityEmbeddingEnabled;
WindowExtensionsImpl() {
@@ -76,9 +75,22 @@
Log.i(TAG, generateLogMessage());
}
+ /**
+ * The min version of the WM Extensions that must be supported in the current platform version.
+ */
+ @VisibleForTesting
+ static int getExtensionsVersionCurrentPlatform() {
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ // Activity Embedding animation customization is the only major feature for v7.
+ return EXTENSIONS_VERSION_V7;
+ } else {
+ return EXTENSIONS_VERSION_V6;
+ }
+ }
+
private String generateLogMessage() {
final StringBuilder logBuilder = new StringBuilder("Initializing Window Extensions, "
- + "vendor API level=" + mVersion);
+ + "vendor API level=" + getExtensionsVersionCurrentPlatform());
final int levelOverride = getLevelOverride();
if (levelOverride != NO_LEVEL_OVERRIDE) {
logBuilder.append(", override to ").append(levelOverride);
@@ -91,7 +103,12 @@
@Override
public int getVendorApiLevel() {
final int levelOverride = getLevelOverride();
- return (levelOverride != NO_LEVEL_OVERRIDE) ? levelOverride : mVersion;
+ return hasLevelOverride() ? levelOverride : getExtensionsVersionCurrentPlatform();
+ }
+
+ @VisibleForTesting
+ boolean hasLevelOverride() {
+ return getLevelOverride() != NO_LEVEL_OVERRIDE;
}
private int getLevelOverride() {
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
index c5aaddc..92f4814 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
@@ -16,7 +16,7 @@
package androidx.window.extensions;
-import static androidx.window.extensions.WindowExtensionsImpl.EXTENSIONS_VERSION_CURRENT_PLATFORM;
+import static androidx.window.extensions.WindowExtensionsImpl.getExtensionsVersionCurrentPlatform;
import static com.google.common.truth.Truth.assertThat;
@@ -59,7 +59,8 @@
@Test
public void testGetVendorApiLevel_extensionsEnabled_matchesCurrentVersion() {
assumeTrue(WindowManager.hasWindowExtensionsEnabled());
- assertThat(mVersion).isEqualTo(EXTENSIONS_VERSION_CURRENT_PLATFORM);
+ assumeFalse(((WindowExtensionsImpl) mExtensions).hasLevelOverride());
+ assertThat(mVersion).isEqualTo(getExtensionsVersionCurrentPlatform());
}
@Test
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 80f6a63..700742a 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
@@ -534,7 +534,8 @@
MultiInstanceHelper multiInstanceHelper,
@ShellMainThread ShellExecutor mainExecutor,
Optional<DesktopTasksLimiter> desktopTasksLimiter,
- Optional<RecentTasksController> recentTasksController) {
+ Optional<RecentTasksController> recentTasksController,
+ InteractionJankMonitor interactionJankMonitor) {
return new DesktopTasksController(context, shellInit, shellCommandHandler, shellController,
displayController, shellTaskOrganizer, syncQueue, rootTaskDisplayAreaOrganizer,
dragAndDropController, transitions, keyguardManager, enterDesktopTransitionHandler,
@@ -542,7 +543,8 @@
dragToDesktopTransitionHandler, desktopModeTaskRepository,
desktopModeLoggerTransitionObserver, launchAdjacentController,
recentsTransitionHandler, multiInstanceHelper,
- mainExecutor, desktopTasksLimiter, recentTasksController.orElse(null));
+ mainExecutor, desktopTasksLimiter, recentTasksController.orElse(null),
+ interactionJankMonitor);
}
@WMSingleton
@@ -568,9 +570,10 @@
Context context,
Transitions transitions,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
- Optional<DesktopTasksLimiter> desktopTasksLimiter) {
+ Optional<DesktopTasksLimiter> desktopTasksLimiter,
+ InteractionJankMonitor interactionJankMonitor) {
return new DragToDesktopTransitionHandler(context, transitions,
- rootTaskDisplayAreaOrganizer);
+ rootTaskDisplayAreaOrganizer, interactionJankMonitor);
}
@WMSingleton
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 de901b5..9fd2c27 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
@@ -49,6 +49,9 @@
import android.window.WindowContainerTransaction
import androidx.annotation.BinderThread
import com.android.internal.annotations.VisibleForTesting
+import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD
+import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE
+import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.internal.protolog.ProtoLog
import com.android.window.flags.Flags
@@ -123,7 +126,8 @@
private val multiInstanceHelper: MultiInstanceHelper,
@ShellMainThread private val mainExecutor: ShellExecutor,
private val desktopTasksLimiter: Optional<DesktopTasksLimiter>,
- private val recentTasksController: RecentTasksController?
+ private val recentTasksController: RecentTasksController?,
+ private val interactionJankMonitor: InteractionJankMonitor
) :
RemoteCallable<DesktopTasksController>,
Transitions.TransitionHandler,
@@ -378,12 +382,15 @@
fun startDragToDesktop(
taskInfo: RunningTaskInfo,
dragToDesktopValueAnimator: MoveToDesktopAnimator,
+ taskSurface: SurfaceControl,
) {
ProtoLog.v(
WM_SHELL_DESKTOP_MODE,
"DesktopTasksController: startDragToDesktop taskId=%d",
taskInfo.taskId
)
+ interactionJankMonitor.begin(taskSurface, context,
+ CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD)
dragToDesktopTransitionHandler.startDragToDesktopTransition(
taskInfo.taskId,
dragToDesktopValueAnimator
@@ -1340,13 +1347,19 @@
fun onDragPositioningEndThroughStatusBar(
inputCoordinates: PointF,
taskInfo: RunningTaskInfo,
+ taskSurface: SurfaceControl,
): IndicatorType {
+ // End the drag_hold CUJ interaction.
+ interactionJankMonitor.end(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD)
val indicator = getVisualIndicator() ?: return IndicatorType.NO_INDICATOR
val indicatorType = indicator.updateIndicatorType(inputCoordinates, taskInfo.windowingMode)
when (indicatorType) {
IndicatorType.TO_DESKTOP_INDICATOR -> {
val displayLayout = displayController.getDisplayLayout(taskInfo.displayId)
?: return IndicatorType.NO_INDICATOR
+ // Start a new jank interaction for the drag release to desktop window animation.
+ interactionJankMonitor.begin(taskSurface, context,
+ CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE, "to_desktop")
if (Flags.enableWindowingDynamicInitialBounds()) {
finalizeDragToDesktop(taskInfo, calculateInitialBounds(displayLayout, taskInfo))
} else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index ddee8fa..9e79eddb0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -30,6 +30,9 @@
import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
import com.android.internal.protolog.ProtoLog
+import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD
+import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE
+import com.android.internal.jank.InteractionJankMonitor
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT
import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT
@@ -57,17 +60,20 @@
private val context: Context,
private val transitions: Transitions,
private val taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
- private val transactionSupplier: Supplier<SurfaceControl.Transaction>
+ private val interactionJankMonitor: InteractionJankMonitor,
+ private val transactionSupplier: Supplier<SurfaceControl.Transaction>,
) : TransitionHandler {
constructor(
context: Context,
transitions: Transitions,
- rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
+ rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
+ interactionJankMonitor: InteractionJankMonitor
) : this(
context,
transitions,
rootTaskDisplayAreaOrganizer,
+ interactionJankMonitor,
Supplier { SurfaceControl.Transaction() }
)
@@ -567,6 +573,8 @@
onTaskResizeAnimationListener.onAnimationEnd(state.draggedTaskId)
startTransitionFinishCb.onTransitionFinished(null /* null */)
clearState()
+ interactionJankMonitor.end(
+ CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE)
}
}
)
@@ -604,6 +612,10 @@
"DragToDesktop: onTransitionConsumed() start transition aborted"
)
state.startAborted = true
+ // Cancel CUJ interaction if the transition is aborted.
+ interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD)
+ } else if (state.cancelTransitionToken != transition) {
+ interactionJankMonitor.cancel(CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE)
}
}
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 8312aef..0e8fd7c 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
@@ -970,7 +970,9 @@
relevantDecor.updateHoverAndPressStatus(ev);
DesktopModeVisualIndicator.IndicatorType resultType =
mDesktopTasksController.onDragPositioningEndThroughStatusBar(
- new PointF(ev.getRawX(), ev.getRawY()), relevantDecor.mTaskInfo);
+ new PointF(ev.getRawX(), ev.getRawY()),
+ relevantDecor.mTaskInfo,
+ relevantDecor.mTaskSurface);
// If we are entering split select, handle will no longer be visible and
// should not be receiving any input.
if (resultType == TO_SPLIT_LEFT_INDICATOR
@@ -1010,7 +1012,7 @@
mContext, mDragToDesktopAnimationStartBounds,
relevantDecor.mTaskInfo, relevantDecor.mTaskSurface);
mDesktopTasksController.startDragToDesktop(relevantDecor.mTaskInfo,
- mMoveToDesktopAnimator);
+ mMoveToDesktopAnimator, relevantDecor.mTaskSurface);
}
}
if (mMoveToDesktopAnimator != null) {
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 8421365..37510ef4 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
@@ -66,6 +66,7 @@
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
import com.android.dx.mockito.inline.extended.ExtendedMockito.never
import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.internal.jank.InteractionJankMonitor
import com.android.window.flags.Flags
import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
import com.android.wm.shell.MockToken
@@ -166,6 +167,9 @@
@Mock lateinit var desktopModeLoggerTransitionObserver: DesktopModeLoggerTransitionObserver
@Mock lateinit var desktopModeVisualIndicator: DesktopModeVisualIndicator
@Mock lateinit var recentTasksController: RecentTasksController
+ @Mock
+ private lateinit var mockInteractionJankMonitor: InteractionJankMonitor
+ @Mock private lateinit var mockSurface: SurfaceControl
private lateinit var mockitoSession: StaticMockitoSession
private lateinit var controller: DesktopTasksController
@@ -248,7 +252,8 @@
multiInstanceHelper,
shellExecutor,
Optional.of(desktopTasksLimiter),
- recentTasksController)
+ recentTasksController,
+ mockInteractionJankMonitor)
}
@After
@@ -2016,7 +2021,7 @@
val task = setUpFullscreenTask()
setUpLandscapeDisplay()
- spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task)
+ spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task, mockSurface)
val wct = getLatestDragToDesktopWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_LANDSCAPE_BOUNDS)
}
@@ -2032,7 +2037,7 @@
val task = setUpFullscreenTask(screenOrientation = SCREEN_ORIENTATION_LANDSCAPE)
setUpLandscapeDisplay()
- spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task)
+ spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task, mockSurface)
val wct = getLatestDragToDesktopWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_LANDSCAPE_BOUNDS)
}
@@ -2049,7 +2054,7 @@
setUpFullscreenTask(screenOrientation = SCREEN_ORIENTATION_PORTRAIT, shouldLetterbox = true)
setUpLandscapeDisplay()
- spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task)
+ spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task, mockSurface)
val wct = getLatestDragToDesktopWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(RESIZABLE_PORTRAIT_BOUNDS)
}
@@ -2066,7 +2071,7 @@
setUpFullscreenTask(isResizable = false, screenOrientation = SCREEN_ORIENTATION_LANDSCAPE)
setUpLandscapeDisplay()
- spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task)
+ spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task, mockSurface)
val wct = getLatestDragToDesktopWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_LANDSCAPE_BOUNDS)
}
@@ -2086,7 +2091,7 @@
shouldLetterbox = true)
setUpLandscapeDisplay()
- spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task)
+ spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task, mockSurface)
val wct = getLatestDragToDesktopWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(UNRESIZABLE_PORTRAIT_BOUNDS)
}
@@ -2102,7 +2107,7 @@
val task = setUpFullscreenTask(deviceOrientation = ORIENTATION_PORTRAIT)
setUpPortraitDisplay()
- spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task)
+ spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task, mockSurface)
val wct = getLatestDragToDesktopWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_PORTRAIT_BOUNDS)
}
@@ -2121,7 +2126,7 @@
screenOrientation = SCREEN_ORIENTATION_PORTRAIT)
setUpPortraitDisplay()
- spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task)
+ spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task, mockSurface)
val wct = getLatestDragToDesktopWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_PORTRAIT_BOUNDS)
}
@@ -2141,7 +2146,7 @@
shouldLetterbox = true)
setUpPortraitDisplay()
- spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task)
+ spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task, mockSurface)
val wct = getLatestDragToDesktopWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(RESIZABLE_LANDSCAPE_BOUNDS)
}
@@ -2161,7 +2166,7 @@
screenOrientation = SCREEN_ORIENTATION_PORTRAIT)
setUpPortraitDisplay()
- spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task)
+ spyController.onDragPositioningEndThroughStatusBar(PointF(800f, 1280f), task, mockSurface)
val wct = getLatestDragToDesktopWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(DEFAULT_PORTRAIT_BOUNDS)
}
@@ -2182,7 +2187,7 @@
shouldLetterbox = true)
setUpPortraitDisplay()
- spyController.onDragPositioningEndThroughStatusBar(PointF(200f, 200f), task)
+ spyController.onDragPositioningEndThroughStatusBar(PointF(200f, 200f), task, mockSurface)
val wct = getLatestDragToDesktopWct()
assertThat(findBoundsChange(wct, task)).isEqualTo(UNRESIZABLE_LANDSCAPE_BOUNDS)
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index bbf523b..e4e2bd2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -15,6 +15,7 @@
import android.window.TransitionInfo.FLAG_IS_WALLPAPER
import android.window.WindowContainerTransaction
import androidx.test.filters.SmallTest
+import com.android.internal.jank.InteractionJankMonitor
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestRunningTaskInfoBuilder
@@ -51,6 +52,8 @@
@Mock private lateinit var taskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer
@Mock private lateinit var splitScreenController: SplitScreenController
@Mock private lateinit var dragAnimator: MoveToDesktopAnimator
+ @Mock
+ private lateinit var mockInteractionJankMonitor: InteractionJankMonitor
private val transactionSupplier = Supplier { mock<SurfaceControl.Transaction>() }
@@ -63,7 +66,8 @@
context,
transitions,
taskDisplayAreaOrganizer,
- transactionSupplier
+ mockInteractionJankMonitor,
+ transactionSupplier,
)
.apply { setSplitScreenController(splitScreenController) }
}
diff --git a/packages/SettingsLib/Spa/build.gradle.kts b/packages/SettingsLib/Spa/build.gradle.kts
index d6345ce..f36344a 100644
--- a/packages/SettingsLib/Spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/build.gradle.kts
@@ -29,7 +29,7 @@
allprojects {
extra["androidTop"] = androidTop
- extra["jetpackComposeVersion"] = "1.7.0-beta02"
+ extra["jetpackComposeVersion"] = "1.7.0-beta05"
}
subprojects {
diff --git a/packages/SettingsLib/Spa/gradle/libs.versions.toml b/packages/SettingsLib/Spa/gradle/libs.versions.toml
index a842009..1cca73a 100644
--- a/packages/SettingsLib/Spa/gradle/libs.versions.toml
+++ b/packages/SettingsLib/Spa/gradle/libs.versions.toml
@@ -15,7 +15,7 @@
#
[versions]
-agp = "8.5.0"
+agp = "8.5.1"
compose-compiler = "1.5.11"
dexmaker-mockito = "2.28.3"
jvm = "17"
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.8-bin.zip b/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.8-bin.zip
deleted file mode 100644
index 77e6ad3..0000000
--- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.8-bin.zip
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.9-bin.zip b/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.9-bin.zip
new file mode 100644
index 0000000..9a97e46
--- /dev/null
+++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-8.9-bin.zip
Binary files differ
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.jar b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.jar
index e644113..2c35211 100644
--- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.jar
+++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
index 91d2a3a..9f29c77 100644
--- a/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
+++ b/packages/SettingsLib/Spa/gradle/wrapper/gradle-wrapper.properties
@@ -16,6 +16,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=gradle-8.8-bin.zip
+distributionUrl=gradle-8.9-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/packages/SettingsLib/Spa/gradlew b/packages/SettingsLib/Spa/gradlew
index b740cf1..f5feea6 100755
--- a/packages/SettingsLib/Spa/gradlew
+++ b/packages/SettingsLib/Spa/gradlew
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -84,7 +86,8 @@
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts
index 492d7c0..ce3d96e 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/spa/build.gradle.kts
@@ -53,14 +53,14 @@
dependencies {
api(project(":SettingsLibColor"))
- api("androidx.appcompat:appcompat:1.7.0-rc01")
- api("androidx.compose.material3:material3:1.3.0-beta02")
+ api("androidx.appcompat:appcompat:1.7.0")
+ api("androidx.compose.material3:material3:1.3.0-beta04")
api("androidx.compose.material:material-icons-extended:$jetpackComposeVersion")
api("androidx.compose.runtime:runtime-livedata:$jetpackComposeVersion")
api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion")
api("androidx.lifecycle:lifecycle-livedata-ktx")
api("androidx.lifecycle:lifecycle-runtime-compose")
- api("androidx.navigation:navigation-compose:2.8.0-beta02")
+ api("androidx.navigation:navigation-compose:2.8.0-beta05")
api("com.github.PhilJay:MPAndroidChart:v3.1.0-alpha")
api("com.google.android.material:material:1.11.0")
debugApi("androidx.compose.ui:ui-tooling:$jetpackComposeVersion")
diff --git a/packages/SystemUI/aconfig/communal.aconfig b/packages/SystemUI/aconfig/communal.aconfig
index afcd8a9..f2b5efa 100644
--- a/packages/SystemUI/aconfig/communal.aconfig
+++ b/packages/SystemUI/aconfig/communal.aconfig
@@ -8,12 +8,3 @@
bug: "304584416"
}
-flag {
- name: "enable_widget_picker_size_filter"
- namespace: "communal"
- description: "Enables passing a size filter to the widget picker"
- bug: "345482907"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
index 665be53..5b328b8 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt
@@ -52,11 +52,19 @@
* and [onStop] methods.
*/
internal interface DragController {
- /** Drag the current scene by [delta] pixels. */
- fun onDrag(delta: Float)
+ /**
+ * Drag the current scene by [delta] pixels.
+ *
+ * @return the consumed [delta]
+ */
+ fun onDrag(delta: Float): Float
- /** Starts a transition to a target scene. */
- fun onStop(velocity: Float, canChangeScene: Boolean)
+ /**
+ * Starts a transition to a target scene.
+ *
+ * @return the consumed [velocity]
+ */
+ fun onStop(velocity: Float, canChangeScene: Boolean): Float
}
internal class DraggableHandlerImpl(
@@ -272,8 +280,10 @@
*
* @return the consumed delta
*/
- override fun onDrag(delta: Float) {
- if (delta == 0f || !isDrivingTransition || swipeTransition.isFinishing) return
+ override fun onDrag(delta: Float): Float {
+ if (delta == 0f || !isDrivingTransition || swipeTransition.isFinishing) {
+ return 0f
+ }
swipeTransition.dragOffset += delta
val (fromScene, acceleratedOffset) =
@@ -289,7 +299,7 @@
if (result == null) {
onStop(velocity = delta, canChangeScene = true)
- return
+ return 0f
}
if (
@@ -314,6 +324,8 @@
updateTransition(swipeTransition)
}
+
+ return delta
}
/**
@@ -351,10 +363,10 @@
}
}
- override fun onStop(velocity: Float, canChangeScene: Boolean) {
+ override fun onStop(velocity: Float, canChangeScene: Boolean): Float {
// The state was changed since the drag started; don't do anything.
if (!isDrivingTransition || swipeTransition.isFinishing) {
- return
+ return 0f
}
// Important: Make sure that all the code here references the current transition when
@@ -440,7 +452,7 @@
if (result == null) {
// We will not animate
swipeTransition.snapToScene(fromScene.key)
- return
+ return 0f
}
val newSwipeTransition =
@@ -462,6 +474,9 @@
animateTo(targetScene = fromScene, targetOffset = 0f)
}
}
+
+ // The onStop animation consumes any remaining velocity.
+ return velocity
}
/**
@@ -1081,17 +1096,13 @@
// TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is
// initiated in a nested child.
controller.onDrag(delta = offsetAvailable)
-
- offsetAvailable
},
onStop = { velocityAvailable ->
val controller = dragController ?: error("Should be called after onStart")
- controller.onStop(velocity = velocityAvailable, canChangeScene = canChangeScene)
-
- dragController = null
- // The onDragStopped animation consumes any remaining velocity.
- velocityAvailable
+ controller
+ .onStop(velocity = velocityAvailable, canChangeScene = canChangeScene)
+ .also { dragController = null }
},
)
}
@@ -1106,7 +1117,7 @@
internal const val OffsetVisibilityThreshold = 0.5f
private object NoOpDragController : DragController {
- override fun onDrag(delta: Float) {}
+ override fun onDrag(delta: Float) = 0f
- override fun onStop(velocity: Float, canChangeScene: Boolean) {}
+ override fun onStop(velocity: Float, canChangeScene: Boolean) = 0f
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
index 7a5a84e..c8bbb14 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt
@@ -212,7 +212,8 @@
draggableHandler: DraggableHandler,
startedPosition: Offset = Offset.Zero,
overSlop: Float = 0f,
- pointersDown: Int = 1
+ pointersDown: Int = 1,
+ expectedConsumed: Boolean = true,
): DragController {
val dragController =
draggableHandler.onDragStarted(
@@ -222,17 +223,23 @@
)
// MultiPointerDraggable will always call onDelta with the initial overSlop right after
- dragController.onDragDelta(pixels = overSlop)
+ dragController.onDragDelta(pixels = overSlop, expectedConsumed = expectedConsumed)
return dragController
}
- fun DragController.onDragDelta(pixels: Float) {
- onDrag(delta = pixels)
+ fun DragController.onDragDelta(pixels: Float, expectedConsumed: Boolean = true) {
+ val consumed = onDrag(delta = pixels)
+ assertThat(consumed).isEqualTo(if (expectedConsumed) pixels else 0f)
}
- fun DragController.onDragStopped(velocity: Float, canChangeScene: Boolean = true) {
- onStop(velocity, canChangeScene)
+ fun DragController.onDragStopped(
+ velocity: Float,
+ canChangeScene: Boolean = true,
+ expectedConsumed: Boolean = true
+ ) {
+ val consumed = onStop(velocity, canChangeScene)
+ assertThat(consumed).isEqualTo(if (expectedConsumed) velocity else 0f)
}
fun NestedScrollConnection.scroll(
@@ -360,10 +367,18 @@
@Test
fun onDragStartedWithoutActionsInBothDirections_stayIdle() = runGestureTest {
- onDragStarted(horizontalDraggableHandler, overSlop = up(fractionOfScreen = 0.3f))
+ onDragStarted(
+ horizontalDraggableHandler,
+ overSlop = up(fractionOfScreen = 0.3f),
+ expectedConsumed = false,
+ )
assertIdle(currentScene = SceneA)
- onDragStarted(horizontalDraggableHandler, overSlop = down(fractionOfScreen = 0.3f))
+ onDragStarted(
+ horizontalDraggableHandler,
+ overSlop = down(fractionOfScreen = 0.3f),
+ expectedConsumed = false,
+ )
assertIdle(currentScene = SceneA)
}
@@ -489,19 +504,19 @@
// start accelaratedScroll and scroll over to B -> null
val dragController2 = onDragStartedImmediately()
- dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f))
- dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f))
+ dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = false)
+ dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = false)
// here onDragStopped is already triggered, but subsequent onDelta/onDragStopped calls may
// still be called. Make sure that they don't crash or change the scene
- dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f))
+ dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = false)
dragController2.onDragStopped(velocity = 0f)
advanceUntilIdle()
assertIdle(SceneB)
// These events can still come in after the animation has settled
- dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f))
+ dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = false)
dragController2.onDragStopped(velocity = 0f)
assertIdle(SceneB)
}
@@ -845,7 +860,7 @@
assertThat(progress).isEqualTo(0.2f)
// this should be ignored, we are scrolling now!
- dragController.onDragStopped(-velocityThreshold)
+ dragController.onDragStopped(-velocityThreshold, expectedConsumed = false)
assertTransition(currentScene = SceneA)
nestedScroll.scroll(available = -offsetY10)
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
index ecafb17..b98400a 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt
@@ -49,6 +49,21 @@
class MultiPointerDraggableTest {
@get:Rule val rule = createComposeRule()
+ private class SimpleDragController(
+ val onDrag: () -> Unit,
+ val onStop: () -> Unit,
+ ) : DragController {
+ override fun onDrag(delta: Float): Float {
+ onDrag()
+ return delta
+ }
+
+ override fun onStop(velocity: Float, canChangeScene: Boolean): Float {
+ onStop()
+ return velocity
+ }
+ }
+
@Test
fun cancellingPointerCallsOnDragStopped() {
val size = 200f
@@ -70,15 +85,10 @@
startDragImmediately = { false },
onDragStarted = { _, _, _ ->
started = true
- object : DragController {
- override fun onDrag(delta: Float) {
- dragged = true
- }
-
- override fun onStop(velocity: Float, canChangeScene: Boolean) {
- stopped = true
- }
- }
+ SimpleDragController(
+ onDrag = { dragged = true },
+ onStop = { stopped = true },
+ )
},
)
)
@@ -142,15 +152,10 @@
startDragImmediately = { true },
onDragStarted = { _, _, _ ->
started = true
- object : DragController {
- override fun onDrag(delta: Float) {
- dragged = true
- }
-
- override fun onStop(velocity: Float, canChangeScene: Boolean) {
- stopped = true
- }
- }
+ SimpleDragController(
+ onDrag = { dragged = true },
+ onStop = { stopped = true },
+ )
},
)
.pointerInput(Unit) {
@@ -218,15 +223,10 @@
startDragImmediately = { false },
onDragStarted = { _, _, _ ->
started = true
- object : DragController {
- override fun onDrag(delta: Float) {
- dragged = true
- }
-
- override fun onStop(velocity: Float, canChangeScene: Boolean) {
- stopped = true
- }
- }
+ SimpleDragController(
+ onDrag = { dragged = true },
+ onStop = { stopped = true },
+ )
},
)
) {
@@ -341,15 +341,10 @@
startDragImmediately = { false },
onDragStarted = { _, _, _ ->
started = true
- object : DragController {
- override fun onDrag(delta: Float) {
- dragged = true
- }
-
- override fun onStop(velocity: Float, canChangeScene: Boolean) {
- stopped = true
- }
- }
+ SimpleDragController(
+ onDrag = { dragged = true },
+ onStop = { stopped = true },
+ )
},
)
) {
@@ -447,15 +442,10 @@
startDragImmediately = { false },
onDragStarted = { _, _, _ ->
verticalStarted = true
- object : DragController {
- override fun onDrag(delta: Float) {
- verticalDragged = true
- }
-
- override fun onStop(velocity: Float, canChangeScene: Boolean) {
- verticalStopped = true
- }
- }
+ SimpleDragController(
+ onDrag = { verticalDragged = true },
+ onStop = { verticalStopped = true },
+ )
},
)
.multiPointerDraggable(
@@ -464,15 +454,10 @@
startDragImmediately = { false },
onDragStarted = { _, _, _ ->
horizontalStarted = true
- object : DragController {
- override fun onDrag(delta: Float) {
- horizontalDragged = true
- }
-
- override fun onStop(velocity: Float, canChangeScene: Boolean) {
- horizontalStopped = true
- }
- }
+ SimpleDragController(
+ onDrag = { horizontalDragged = true },
+ onStop = { horizontalStopped = true },
+ )
},
)
)
@@ -567,11 +552,10 @@
},
onDragStarted = { _, _, _ ->
started = true
- object : DragController {
- override fun onDrag(delta: Float) {}
-
- override fun onStop(velocity: Float, canChangeScene: Boolean) {}
- }
+ SimpleDragController(
+ onDrag = { /* do nothing */ },
+ onStop = { /* do nothing */ },
+ )
},
)
) {}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index b1e5135..830f543 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -24,7 +24,6 @@
import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import com.android.internal.logging.UiEventLogger
-import com.android.systemui.Flags.enableWidgetPickerSizeFilter
import com.android.systemui.communal.data.model.CommunalWidgetCategories
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalPrefsInteractor
@@ -176,16 +175,14 @@
return Intent(Intent.ACTION_PICK).apply {
setPackage(packageName)
- if (enableWidgetPickerSizeFilter()) {
- putExtra(
- EXTRA_DESIRED_WIDGET_WIDTH,
- resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_width)
- )
- putExtra(
- EXTRA_DESIRED_WIDGET_HEIGHT,
- resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_height)
- )
- }
+ putExtra(
+ EXTRA_DESIRED_WIDGET_WIDTH,
+ resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_width)
+ )
+ putExtra(
+ EXTRA_DESIRED_WIDGET_HEIGHT,
+ resources.getDimensionPixelSize(R.dimen.communal_widget_picker_desired_height)
+ )
putExtra(
AppWidgetManager.EXTRA_CATEGORY_FILTER,
CommunalWidgetCategories.defaultCategories
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index c912616..b9d24ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -51,6 +51,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Pair;
import android.util.SparseArray;
import android.view.KeyEvent;
@@ -200,6 +201,7 @@
* event.
*/
private int mLastUpdatedImeDisplayId = INVALID_DISPLAY;
+ private final Context mContext;
private final DisplayTracker mDisplayTracker;
private final @Nullable CommandRegistry mRegistry;
private final @Nullable DumpHandler mDumpHandler;
@@ -571,6 +573,7 @@
DumpHandler dumpHandler,
Lazy<PowerInteractor> powerInteractor
) {
+ mContext = context;
mDisplayTracker = displayTracker;
mRegistry = registry;
mDumpHandler = dumpHandler;
@@ -1209,7 +1212,12 @@
boolean showImeSwitcher) {
if (displayId == INVALID_DISPLAY) return;
- if (mLastUpdatedImeDisplayId != displayId
+ boolean isConcurrentMultiUserModeEnabled = UserManager.isVisibleBackgroundUsersEnabled()
+ && mContext.getResources().getBoolean(android.R.bool.config_perDisplayFocusEnabled)
+ && android.view.inputmethod.Flags.concurrentInputMethods();
+
+ if (!isConcurrentMultiUserModeEnabled
+ && mLastUpdatedImeDisplayId != displayId
&& mLastUpdatedImeDisplayId != INVALID_DISPLAY) {
// Set previous NavBar's IME window status as invisible when IME
// window switched to another display for single-session IME case.
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index ad8f5e1..668852b 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -31,12 +31,14 @@
import android.metrics.LogMaker;
import android.os.UserManager;
import android.service.autofill.Dataset;
+import android.service.autofill.FillResponse;
import android.service.autofill.InternalSanitizer;
import android.service.autofill.SaveInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
+import android.util.SparseArray;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
@@ -374,4 +376,50 @@
private interface ViewNodeFilter {
boolean matches(ViewNode node);
}
+
+ public static class SaveInfoStats {
+ public int saveInfoCount;
+ public int saveDataTypeCount;
+
+ public SaveInfoStats(int saveInfoCount, int saveDataTypeCount) {
+ this.saveInfoCount = saveInfoCount;
+ this.saveDataTypeCount = saveDataTypeCount;
+ }
+ }
+
+ /**
+ * Get statistic information of save info given a sparse array of fill responses.
+ *
+ * Specifically the statistic includes
+ * 1. how many save info the current session has.
+ * 2. How many distinct save data types current session has.
+ *
+ * @return SaveInfoStats returns the above two number in a SaveInfoStats object
+ */
+ public static SaveInfoStats getSaveInfoStatsFromFillResponses(
+ SparseArray<FillResponse> fillResponses) {
+ if (fillResponses == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "getSaveInfoStatsFromFillResponses(): fillResponse sparse array is "
+ + "null");
+ }
+ return new SaveInfoStats(-1, -1);
+ }
+ int numSaveInfos = 0;
+ int numSaveDataTypes = 0;
+ ArraySet<Integer> saveDataTypeSeen = new ArraySet<>();
+ final int numResponses = fillResponses.size();
+ for (int responseNum = 0; responseNum < numResponses; responseNum++) {
+ final FillResponse response = fillResponses.valueAt(responseNum);
+ if (response != null && response.getSaveInfo() != null) {
+ numSaveInfos += 1;
+ int saveDataType = response.getSaveInfo().getType();
+ if (!saveDataTypeSeen.contains(saveDataType)) {
+ saveDataTypeSeen.add(saveDataType);
+ numSaveDataTypes += 1;
+ }
+ }
+ }
+ return new SaveInfoStats(numSaveInfos, numSaveDataTypes);
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
index a5ec2ba..49ca297 100644
--- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
@@ -854,7 +854,6 @@
mCallingAppUid,
event.mIsCredentialRequest,
event.mWebviewRequestedCredential,
- event.mFilteredFillabaleViewCount,
event.mViewFillableTotalCount,
event.mViewFillFailureCount,
event.mFocusedId,
@@ -868,6 +867,7 @@
event.mFocusedVirtualAutofillId,
event.mFieldFirstLength,
event.mFieldLastLength,
+ event.mFilteredFillabaleViewCount,
event.mViewFailedPriorToRefillCount,
event.mViewFilledSuccessfullyOnRefillCount,
event.mViewFailedOnRefillCount,
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index c6ddc16..21df7a5 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -70,6 +70,7 @@
import static com.android.server.autofill.Helper.containsCharsInOrder;
import static com.android.server.autofill.Helper.createSanitizers;
import static com.android.server.autofill.Helper.getNumericValue;
+import static com.android.server.autofill.Helper.SaveInfoStats;
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
import static com.android.server.autofill.Helper.toArray;
@@ -3203,11 +3204,6 @@
return saveInfo == null ? 0 : saveInfo.getFlags();
}
- static class SaveInfoStats {
- public int saveInfoCount;
- public int saveDataTypeCount;
- }
-
/**
* Get statistic information of save info in current session. Specifically
* 1. how many save info the current session has.
@@ -3217,42 +3213,13 @@
*/
@GuardedBy("mLock")
private SaveInfoStats getSaveInfoStatsLocked() {
- SaveInfoStats retSaveInfoStats = new SaveInfoStats();
- retSaveInfoStats.saveInfoCount = -1;
- retSaveInfoStats.saveDataTypeCount = -1;
-
if (mContexts == null) {
if (sVerbose) {
Slog.v(TAG, "getSaveInfoStatsLocked(): mContexts is null");
}
- } else if (mResponses == null) {
- // Happens when the activity / session was finished before the service replied, or
- // when the service cannot autofill it (and returned a null response).
- if (sVerbose) {
- Slog.v(TAG, "getSaveInfoStatsLocked(): mResponses is null");
- }
- return retSaveInfoStats;
- } else {
- int numSaveInfos = 0;
- int numSaveDataTypes = 0;
- ArraySet<Integer> saveDataTypeSeen = new ArraySet<>();
- final int numResponses = mResponses.size();
- for (int responseNum = 0; responseNum < numResponses; responseNum++) {
- final FillResponse response = mResponses.valueAt(responseNum);
- if (response != null && response.getSaveInfo() != null) {
- numSaveInfos += 1;
- int saveDataType = response.getSaveInfo().getType();
- if (!saveDataTypeSeen.contains(saveDataType)) {
- saveDataTypeSeen.add(saveDataType);
- numSaveDataTypes += 1;
- }
- }
- }
- retSaveInfoStats.saveInfoCount = numSaveInfos;
- retSaveInfoStats.saveDataTypeCount = numSaveDataTypes;
+ return new SaveInfoStats(-1, -1);
}
-
- return retSaveInfoStats;
+ return Helper.getSaveInfoStatsFromFillResponses(mResponses);
}
/**
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 69ee8fc..cf0befa 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16961,16 +16961,24 @@
int userId = UserHandle.getCallingUserId();
- if (UserManager.isVisibleBackgroundUsersEnabled() && userId != getCurrentUserId()) {
- // The check is added mainly for auto devices. On auto devices, it is possible that
- // multiple users are visible simultaneously using visible background users.
- // In such cases, it is desired that only the current user (not the visible background
- // user) can change the locale and other persistent settings of the device.
- Slog.w(TAG, "Only current user is allowed to update persistent configuration if "
- + "visible background users are enabled. Current User" + getCurrentUserId()
- + ". Calling User: " + userId);
- throw new SecurityException("Only current user is allowed to update persistent "
- + "configuration.");
+ if (UserManager.isVisibleBackgroundUsersEnabled()) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ if (userId != getCurrentUserId()) {
+ // The check is added mainly for auto devices. On auto devices, it is
+ // possible that multiple users are visible simultaneously using visible
+ // background users. In such cases, it is desired that only the current user
+ // (not the visible background user) can change the locale and other persistent
+ // settings of the device.
+ Slog.w(TAG, "Only current user is allowed to update persistent configuration "
+ + "if visible background users are enabled. Current User"
+ + getCurrentUserId() + ". Calling User: " + userId);
+ throw new SecurityException("Only current user is allowed to update persistent "
+ + "configuration.");
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
}
mActivityTaskManager.updatePersistentConfiguration(values, userId);
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 803b125..621c090 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -702,7 +702,7 @@
}
}
- private final class BinderService extends IMediaProjectionManager.Stub {
+ final class BinderService extends IMediaProjectionManager.Stub {
BinderService(Context context) {
super(PermissionEnforcer.fromContext(context));
@@ -891,6 +891,13 @@
@Override
public void requestConsentForInvalidProjection(@NonNull IMediaProjection projection) {
requestConsentForInvalidProjection_enforcePermission();
+
+ if (android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()
+ && mKeyguardManager.isKeyguardLocked()) {
+ Slog.v(TAG, "Reusing token: Won't request consent while the keyguard is locked");
+ return;
+ }
+
synchronized (mLock) {
if (!isCurrentProjection(projection)) {
Slog.v(TAG, "Reusing token: Won't request consent again for a token that "
diff --git a/services/core/java/com/android/server/net/NetworkManagementService.java b/services/core/java/com/android/server/net/NetworkManagementService.java
index 5b91118..74f0d9c 100644
--- a/services/core/java/com/android/server/net/NetworkManagementService.java
+++ b/services/core/java/com/android/server/net/NetworkManagementService.java
@@ -831,66 +831,6 @@
}
@Override
- public boolean getIpForwardingEnabled() throws IllegalStateException{
- PermissionUtils.enforceNetworkStackPermission(mContext);
- throw new UnsupportedOperationException("NMS#getIpForwardingEnabled not supported in V+");
- }
-
- @Override
- public void setIpForwardingEnabled(boolean enable) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- throw new UnsupportedOperationException("NMS#setIpForwardingEnabled not supported in V+");
- }
-
- @Override
- public void startTethering(String[] dhcpRange) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- throw new UnsupportedOperationException("NMS#startTethering not supported in V+");
- }
-
- @Override
- public void stopTethering() {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- throw new UnsupportedOperationException("NMS#stopTethering not supported in V+");
- }
-
- @Override
- public boolean isTetheringStarted() {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- throw new UnsupportedOperationException("NMS#isTetheringStarted not supported in V+");
- }
-
- @Override
- public void tetherInterface(String iface) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- throw new UnsupportedOperationException("NMS#tetherInterface not supported in V+");
- }
-
- @Override
- public void untetherInterface(String iface) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- throw new UnsupportedOperationException("NMS#untetherInterface not supported in V+");
- }
-
- @Override
- public String[] listTetheredInterfaces() {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- throw new UnsupportedOperationException("NMS#listTetheredInterfaces not supported in V+");
- }
-
- @Override
- public void enableNat(String internalInterface, String externalInterface) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- throw new UnsupportedOperationException("NMS#enableNat not supported in V+");
- }
-
- @Override
- public void disableNat(String internalInterface, String externalInterface) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
- throw new UnsupportedOperationException("NMS#disableNat not supported in V+");
- }
-
- @Override
public void setInterfaceQuota(String iface, long quotaBytes) {
PermissionUtils.enforceNetworkStackPermission(mContext);
diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
index fde23b7..9b64488 100644
--- a/services/core/java/com/android/server/policy/ModifierShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
@@ -16,6 +16,7 @@
package com.android.server.policy;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.role.RoleManager;
import android.content.ActivityNotFoundException;
@@ -248,31 +249,7 @@
+ " className=" + className + " shortcutChar=" + shortcutChar);
continue;
}
- ComponentName componentName = new ComponentName(packageName, className);
- try {
- mPackageManager.getActivityInfo(componentName,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_UNINSTALLED_PACKAGES);
- } catch (PackageManager.NameNotFoundException e) {
- String[] packages = mPackageManager.canonicalToCurrentPackageNames(
- new String[] { packageName });
- componentName = new ComponentName(packages[0], className);
- try {
- mPackageManager.getActivityInfo(componentName,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_UNINSTALLED_PACKAGES);
- } catch (PackageManager.NameNotFoundException e1) {
- Log.w(TAG, "Unable to add bookmark: " + packageName
- + "/" + className + " not found.");
- continue;
- }
- }
-
- intent = new Intent(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_LAUNCHER);
- intent.setComponent(componentName);
+ intent = resolveComponentNameIntent(packageName, className);
} else if (categoryName != null) {
if (roleName != null) {
Log.w(TAG, "Cannot specify role bookmark when category is present for"
@@ -310,6 +287,32 @@
}
}
+ @Nullable
+ private Intent resolveComponentNameIntent(String packageName, String className) {
+ int flags = PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES;
+ ComponentName componentName = new ComponentName(packageName, className);
+ try {
+ mPackageManager.getActivityInfo(componentName, flags);
+ } catch (PackageManager.NameNotFoundException e) {
+ String[] packages = mPackageManager.canonicalToCurrentPackageNames(
+ new String[] { packageName });
+ componentName = new ComponentName(packages[0], className);
+ try {
+ mPackageManager.getActivityInfo(componentName, flags);
+ } catch (PackageManager.NameNotFoundException e1) {
+ Log.w(TAG, "Unable to add bookmark: " + packageName
+ + "/" + className + " not found.");
+ return null;
+ }
+ }
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ intent.setComponent(componentName);
+ return intent;
+ }
+
void registerShortcutKey(long shortcutCode, IShortcutService shortcutService)
throws RemoteException {
IShortcutService service = mShortcutKeyServices.get(shortcutCode);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8419a60..df97313 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2402,7 +2402,7 @@
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
}
- mWindowManagerInternal.registerAppTransitionListener(new AppTransitionListener() {
+ final var transitionListener = new AppTransitionListener(DEFAULT_DISPLAY) {
@Override
public int onAppTransitionStartingLocked(long statusBarAnimationStartTime,
long statusBarAnimationDuration) {
@@ -2436,7 +2436,8 @@
mLockAfterDreamingTransitionFinished = false;
}
}
- });
+ };
+ mWindowManagerInternal.registerAppTransitionListener(transitionListener);
mKeyguardDrawnTimeout = mContext.getResources().getInteger(
com.android.internal.R.integer.config_keyguardDrawnTimeout);
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 1b7bf89..4052a64 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -16356,6 +16356,7 @@
mBluetoothPowerStatsCollector.collectAndDump(pw);
mCameraPowerStatsCollector.collectAndDump(pw);
mGnssPowerStatsCollector.collectAndDump(pw);
+ mCustomEnergyConsumerPowerStatsCollector.collectAndDump(pw);
}
private final Runnable mWriteAsyncRunnable = () -> {
diff --git a/services/core/java/com/android/server/power/stats/CustomEnergyConsumerPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/CustomEnergyConsumerPowerStatsCollector.java
index 1191901..0273ba6 100644
--- a/services/core/java/com/android/server/power/stats/CustomEnergyConsumerPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/CustomEnergyConsumerPowerStatsCollector.java
@@ -19,6 +19,7 @@
import android.hardware.power.stats.EnergyConsumerType;
import android.os.BatteryConsumer;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -65,4 +66,12 @@
}
return success;
}
+
+ @Override
+ public void collectAndDump(PrintWriter pw) {
+ ensureInitialized();
+ for (int i = 0; i < mCollectors.size(); i++) {
+ mCollectors.get(i).collectAndDump(pw);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java b/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java
index cace941..ce11fa0 100644
--- a/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/EnergyConsumerPowerStatsCollector.java
@@ -176,9 +176,12 @@
for (EnergyConsumerAttribution attribution : perUid) {
int uid = mUidResolver.mapUid(attribution.uid);
- long lastEnergy = mLastConsumerEnergyPerUid.get(uid);
- long deltaEnergy = attribution.energyUWs - lastEnergy;
+ long lastEnergy = mLastConsumerEnergyPerUid.get(uid, ENERGY_UNSPECIFIED);
mLastConsumerEnergyPerUid.put(uid, attribution.energyUWs);
+ if (lastEnergy == ENERGY_UNSPECIFIED) {
+ continue;
+ }
+ long deltaEnergy = attribution.energyUWs - lastEnergy;
if (deltaEnergy <= 0) {
continue;
}
@@ -189,7 +192,8 @@
}
mLayout.setUidConsumedEnergy(uidStats, 0,
- mLayout.getUidConsumedEnergy(uidStats, 0) + deltaEnergy);
+ mLayout.getUidConsumedEnergy(uidStats, 0)
+ + uJtoUc(deltaEnergy, averageVoltage));
}
}
}
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsCollector.java b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
index d9f6c1f..f5b0005 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsCollector.java
@@ -196,12 +196,11 @@
}
IndentingPrintWriter out = new IndentingPrintWriter(pw);
- out.print(getClass().getSimpleName());
if (!isEnabled()) {
+ out.print(getClass().getSimpleName());
out.println(": disabled");
return;
}
- out.println();
ArrayList<PowerStats> collected = new ArrayList<>();
Consumer<PowerStats> consumer = collected::add;
@@ -215,11 +214,9 @@
removeConsumer(consumer);
}
- out.increaseIndent();
for (PowerStats stats : collected) {
stats.dump(out);
}
- out.decreaseIndent();
}
private void awaitCompletion() {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 400919a..516fc65 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -53,7 +53,6 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
-import static android.app.WindowConfiguration.isFloating;
import static android.app.admin.DevicePolicyResources.Drawables.Source.PROFILE_SWITCH_ANIMATION;
import static android.app.admin.DevicePolicyResources.Drawables.Style.OUTLINE;
import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
@@ -336,7 +335,6 @@
import android.service.dreams.DreamActivity;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArraySet;
-import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.util.MergedConfiguration;
@@ -8648,7 +8646,14 @@
resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
}
- applySizeOverrideIfNeeded(newParentConfiguration, parentWindowingMode, resolvedConfig);
+ applySizeOverrideIfNeeded(
+ mDisplayContent,
+ info.applicationInfo,
+ newParentConfiguration,
+ resolvedConfig,
+ mOptOutEdgeToEdge,
+ hasFixedRotationTransform(),
+ getCompatDisplayInsets() != null);
mResolveConfigHint.resetTmpOverrides();
logAppCompatState();
@@ -8658,100 +8663,6 @@
return Rect.copyOrNull(mResolveConfigHint.mParentAppBoundsOverride);
}
- /**
- * If necessary, override configuration fields related to app bounds.
- * This will happen when the app is targeting SDK earlier than 35.
- * The insets and configuration has decoupled since SDK level 35, to make the system
- * compatible to existing apps, override the configuration with legacy metrics. In legacy
- * metrics, fields such as appBounds will exclude some of the system bar areas.
- * The override contains all potentially affected fields in Configuration, including
- * screenWidthDp, screenHeightDp, smallestScreenWidthDp, and orientation.
- * All overrides to those fields should be in this method.
- *
- * TODO: Consider integrate this with computeConfigByResolveHint()
- */
- private void applySizeOverrideIfNeeded(Configuration newParentConfiguration,
- int parentWindowingMode, Configuration inOutConfig) {
- if (mDisplayContent == null) {
- return;
- }
- final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds();
- int rotation = newParentConfiguration.windowConfiguration.getRotation();
- if (rotation == ROTATION_UNDEFINED && !isFixedRotationTransforming()) {
- rotation = mDisplayContent.getRotation();
- }
- if (!mOptOutEdgeToEdge && (!mResolveConfigHint.mUseOverrideInsetsForConfig
- || getCompatDisplayInsets() != null
- || (isFloating(parentWindowingMode)
- // Check the requested windowing mode of activity as well in case it is
- // switching between PiP and fullscreen.
- && (inOutConfig.windowConfiguration.getWindowingMode()
- == WINDOWING_MODE_UNDEFINED
- || isFloating(inOutConfig.windowConfiguration.getWindowingMode())))
- || rotation == ROTATION_UNDEFINED)) {
- // If the insets configuration decoupled logic is not enabled for the app, or the app
- // already has a compat override, or the context doesn't contain enough info to
- // calculate the override, skip the override.
- return;
- }
- // Make sure the orientation related fields will be updated by the override insets, because
- // fixed rotation has assigned the fields from display's configuration.
- if (hasFixedRotationTransform()) {
- inOutConfig.windowConfiguration.setAppBounds(null);
- inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
- inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
- inOutConfig.smallestScreenWidthDp = Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
- inOutConfig.orientation = ORIENTATION_UNDEFINED;
- }
-
- // Override starts here.
- final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
- final int dw = rotated ? mDisplayContent.mBaseDisplayHeight
- : mDisplayContent.mBaseDisplayWidth;
- final int dh = rotated ? mDisplayContent.mBaseDisplayWidth
- : mDisplayContent.mBaseDisplayHeight;
- final Rect nonDecorInsets = mDisplayContent.getDisplayPolicy()
- .getDecorInsetsInfo(rotation, dw, dh).mOverrideNonDecorInsets;
- // This should be the only place override the configuration for ActivityRecord. Override
- // the value if not calculated yet.
- Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
- if (outAppBounds == null || outAppBounds.isEmpty()) {
- inOutConfig.windowConfiguration.setAppBounds(parentBounds);
- outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
- outAppBounds.inset(nonDecorInsets);
- }
- float density = inOutConfig.densityDpi;
- if (density == Configuration.DENSITY_DPI_UNDEFINED) {
- density = newParentConfiguration.densityDpi;
- }
- density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
- if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
- inOutConfig.screenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
- }
- if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
- inOutConfig.screenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
- }
- if (inOutConfig.smallestScreenWidthDp
- == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
- && parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
- // For the case of PIP transition and multi-window environment, the
- // smallestScreenWidthDp is handled already. Override only if the app is in
- // fullscreen.
- final DisplayInfo info = new DisplayInfo(mDisplayContent.getDisplayInfo());
- mDisplayContent.computeSizeRanges(info, rotated, dw, dh,
- mDisplayContent.getDisplayMetrics().density,
- inOutConfig, true /* overrideConfig */);
- }
-
- // It's possible that screen size will be considered in different orientation with or
- // without considering the system bar insets. Override orientation as well.
- if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
- inOutConfig.orientation =
- (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
- ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
- }
- }
-
private void computeConfigByResolveHint(@NonNull Configuration resolvedConfig,
@NonNull Configuration parentConfig) {
task.computeConfigResourceOverrides(resolvedConfig, parentConfig, mResolveConfigHint);
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 8421765..0f8d68b 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -166,15 +166,14 @@
return null;
}
- // Move focus to the top embedded window if possible
- if (mWindowManagerService.moveFocusToAdjacentEmbeddedWindow(window)) {
- window = wmService.getFocusedWindowLocked();
- if (window == null) {
- Slog.e(TAG, "New focused window is null, returning null.");
- return null;
- }
+ // Updating the window to the most recently used one among the embedded windows
+ // that are displayed adjacently, unless the IME is visible.
+ // When the IME is visible, the IME is displayed on top of embedded activities.
+ // In that case, the back event should still be delivered to focused activity in
+ // order to dismiss the IME.
+ if (!window.getDisplayContent().getImeContainer().isVisible()) {
+ window = mWindowManagerService.getMostRecentUsedEmbeddedWindowForBack(window);
}
-
if (!window.isDrawn()) {
ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
"Focused window didn't have a valid surface drawn.");
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index efd5202..3ebaf03 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -22,14 +22,23 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
+import static android.app.WindowConfiguration.isFloating;
import static android.app.WindowConfiguration.windowingModeToString;
import static android.app.WindowConfigurationProto.WINDOWING_MODE;
import static android.content.ConfigurationProto.WINDOW_CONFIGURATION;
+import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED;
+import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
import static com.android.server.wm.ConfigurationContainerProto.FULL_CONFIGURATION;
import static com.android.server.wm.ConfigurationContainerProto.MERGED_OVERRIDE_CONFIGURATION;
@@ -38,11 +47,14 @@
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.app.WindowConfiguration;
+import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.LocaleList;
+import android.util.DisplayMetrics;
import android.util.proto.ProtoOutputStream;
+import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
@@ -173,6 +185,110 @@
mResolvedOverrideConfiguration.setTo(mRequestedOverrideConfiguration);
}
+ /**
+ * If necessary, override configuration fields related to app bounds.
+ * This will happen when the app is targeting SDK earlier than 35.
+ * The insets and configuration has decoupled since SDK level 35, to make the system
+ * compatible to existing apps, override the configuration with legacy metrics. In legacy
+ * metrics, fields such as appBounds will exclude some of the system bar areas.
+ * The override contains all potentially affected fields in Configuration, including
+ * screenWidthDp, screenHeightDp, smallestScreenWidthDp, and orientation.
+ * All overrides to those fields should be in this method.
+ *
+ * TODO: Consider integrate this with computeConfigByResolveHint()
+ */
+ static void applySizeOverrideIfNeeded(DisplayContent displayContent, ApplicationInfo appInfo,
+ Configuration newParentConfiguration, Configuration inOutConfig,
+ boolean optsOutEdgeToEdge, boolean hasFixedRotationTransform,
+ boolean hasCompatDisplayInsets) {
+ if (displayContent == null) {
+ return;
+ }
+ final boolean useOverrideInsetsForConfig =
+ displayContent.mWmService.mFlags.mInsetsDecoupledConfiguration
+ ? !appInfo.isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED)
+ && !appInfo.isChangeEnabled(
+ OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION)
+ : appInfo.isChangeEnabled(OVERRIDE_ENABLE_INSETS_DECOUPLED_CONFIGURATION);
+ final int parentWindowingMode =
+ newParentConfiguration.windowConfiguration.getWindowingMode();
+ final boolean isFloating = isFloating(parentWindowingMode)
+ // Check the requested windowing mode of activity as well in case it is
+ // switching between PiP and fullscreen.
+ && (inOutConfig.windowConfiguration.getWindowingMode() == WINDOWING_MODE_UNDEFINED
+ || isFloating(inOutConfig.windowConfiguration.getWindowingMode()));
+ int rotation = newParentConfiguration.windowConfiguration.getRotation();
+ if (rotation == ROTATION_UNDEFINED && !hasFixedRotationTransform) {
+ rotation = displayContent.getRotation();
+ }
+ if (!optsOutEdgeToEdge && (!useOverrideInsetsForConfig
+ || hasCompatDisplayInsets
+ || isFloating
+ || rotation == ROTATION_UNDEFINED)) {
+ // If the insets configuration decoupled logic is not enabled for the app, or the app
+ // already has a compat override, or the context doesn't contain enough info to
+ // calculate the override, skip the override.
+ return;
+ }
+ // Make sure the orientation related fields will be updated by the override insets, because
+ // fixed rotation has assigned the fields from display's configuration.
+ if (hasFixedRotationTransform) {
+ inOutConfig.windowConfiguration.setAppBounds(null);
+ inOutConfig.screenWidthDp = Configuration.SCREEN_WIDTH_DP_UNDEFINED;
+ inOutConfig.screenHeightDp = Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
+ inOutConfig.smallestScreenWidthDp = Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
+ inOutConfig.orientation = ORIENTATION_UNDEFINED;
+ }
+
+ // Override starts here.
+ final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
+ final int dw = rotated
+ ? displayContent.mBaseDisplayHeight
+ : displayContent.mBaseDisplayWidth;
+ final int dh = rotated
+ ? displayContent.mBaseDisplayWidth
+ : displayContent.mBaseDisplayHeight;
+ // This should be the only place override the configuration for ActivityRecord. Override
+ // the value if not calculated yet.
+ Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+ if (outAppBounds == null || outAppBounds.isEmpty()) {
+ inOutConfig.windowConfiguration.setAppBounds(
+ newParentConfiguration.windowConfiguration.getBounds());
+ outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+ outAppBounds.inset(displayContent.getDisplayPolicy()
+ .getDecorInsetsInfo(rotation, dw, dh).mOverrideNonDecorInsets);
+ }
+ float density = inOutConfig.densityDpi;
+ if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+ density = newParentConfiguration.densityDpi;
+ }
+ density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+ inOutConfig.screenWidthDp = (int) (outAppBounds.width() / density + 0.5f);
+ }
+ if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+ inOutConfig.screenHeightDp = (int) (outAppBounds.height() / density + 0.5f);
+ }
+ if (inOutConfig.smallestScreenWidthDp == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED
+ && parentWindowingMode == WINDOWING_MODE_FULLSCREEN) {
+ // For the case of PIP transition and multi-window environment, the
+ // smallestScreenWidthDp is handled already. Override only if the app is in
+ // fullscreen.
+ final DisplayInfo info = new DisplayInfo(displayContent.getDisplayInfo());
+ displayContent.computeSizeRanges(info, rotated, dw, dh,
+ displayContent.getDisplayMetrics().density,
+ inOutConfig, true /* overrideConfig */);
+ }
+
+ // It's possible that screen size will be considered in different orientation with or
+ // without considering the system bar insets. Override orientation as well.
+ if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
+ inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
+ ? ORIENTATION_PORTRAIT
+ : ORIENTATION_LANDSCAPE;
+ }
+ }
+
/** Returns {@code true} if requested override override configuration is not empty. */
boolean hasRequestedOverrideConfiguration() {
return mHasOverrideConfiguration;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9371149..fa60368 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3895,6 +3895,22 @@
}
/**
+ * Returns the focused window of the given Activity if the Activity is focused.
+ */
+ WindowState findFocusedWindow(ActivityRecord activityRecord) {
+ final ActivityRecord tmpApp = mFocusedApp;
+ mTmpWindow = null;
+ try {
+ mFocusedApp = activityRecord;
+ // mFindFocusedWindow will populate mTmpWindow with the new focused window when found.
+ activityRecord.forAllWindows(mFindFocusedWindow, true /* traverseTopToBottom */);
+ } finally {
+ mFocusedApp = tmpApp;
+ }
+ return mTmpWindow;
+ }
+
+ /**
* Update the focused window and make some adjustments if the focus has changed.
*
* @param mode Indicates the situation we are in. Possible modes are:
@@ -6911,6 +6927,10 @@
/** Whether {@link #mAnimatingRecents} is going to be the top activity. */
private boolean mRecentsWillBeTop;
+ FixedRotationTransitionListener() {
+ super(DisplayContent.this.mDisplayId);
+ }
+
/**
* If the recents activity has a fixed orientation which is different from the current top
* activity, it will be rotated before being shown so we avoid a screen rotation animation
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 80362a4..c3339cd 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -588,7 +588,7 @@
gesturesPointerEventCallbacks);
displayContent.registerPointerEventListener(mSystemGestures);
}
- mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() {
+ mAppTransitionListener = new WindowManagerInternal.AppTransitionListener(displayId) {
private Runnable mAppTransitionPending = () -> {
StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index c26684f..cc95518 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -39,7 +39,6 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.NonNull;
@@ -537,27 +536,11 @@
@Override
public boolean startMovingTask(IWindow window, float startX, float startY) {
- if (DEBUG_TASK_POSITIONING) Slog.d(
- TAG_WM, "startMovingTask: {" + startX + "," + startY + "}");
-
- final long ident = Binder.clearCallingIdentity();
- try {
- return mService.mTaskPositioningController.startMovingTask(window, startX, startY);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ return false;
}
@Override
public void finishMovingTask(IWindow window) {
- if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishMovingTask");
-
- final long ident = Binder.clearCallingIdentity();
- try {
- mService.mTaskPositioningController.finishTaskPositioning(window);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
deleted file mode 100644
index 972dd2e..0000000
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.app.ActivityTaskManager.RESIZE_MODE_USER;
-import static android.app.ActivityTaskManager.RESIZE_MODE_USER_FORCED;
-import static android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
-import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-
-import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM;
-import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_LEFT;
-import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE;
-import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_RIGHT;
-import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_TOP;
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.dipToPixel;
-import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
-import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
-
-import static java.util.concurrent.CompletableFuture.completedFuture;
-
-import android.annotation.NonNull;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.InputConfig;
-import android.os.RemoteException;
-import android.os.Trace;
-import android.util.DisplayMetrics;
-import android.util.Slog;
-import android.view.BatchedInputEventReceiver;
-import android.view.InputApplicationHandle;
-import android.view.InputChannel;
-import android.view.InputDevice;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
-import android.view.InputWindowHandle;
-import android.view.MotionEvent;
-import android.view.WindowManager;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.TaskResizingAlgorithm;
-import com.android.internal.policy.TaskResizingAlgorithm.CtrlType;
-import com.android.internal.protolog.ProtoLog;
-
-import java.util.concurrent.CompletableFuture;
-
-class TaskPositioner implements IBinder.DeathRecipient {
- private static final boolean DEBUG_ORIENTATION_VIOLATIONS = false;
- private static final String TAG_LOCAL = "TaskPositioner";
- private static final String TAG = TAG_WITH_CLASS_NAME ? TAG_LOCAL : TAG_WM;
-
- private static Factory sFactory;
-
- public static final float RESIZING_HINT_ALPHA = 0.5f;
-
- public static final int RESIZING_HINT_DURATION_MS = 0;
-
- private final WindowManagerService mService;
- private InputEventReceiver mInputEventReceiver;
- private DisplayContent mDisplayContent;
- private Rect mTmpRect = new Rect();
- private int mMinVisibleWidth;
- private int mMinVisibleHeight;
-
- @VisibleForTesting
- Task mTask;
- WindowState mWindow;
- private boolean mResizing;
- private boolean mPreserveOrientation;
- private boolean mStartOrientationWasLandscape;
- private final Rect mWindowOriginalBounds = new Rect();
- private final Rect mWindowDragBounds = new Rect();
- private final Point mMaxVisibleSize = new Point();
- private float mStartDragX;
- private float mStartDragY;
- @CtrlType
- private int mCtrlType = CTRL_NONE;
- @VisibleForTesting
- boolean mDragEnded;
- IBinder mClientCallback;
-
- InputChannel mClientChannel;
- InputApplicationHandle mDragApplicationHandle;
- InputWindowHandle mDragWindowHandle;
-
- /** Use {@link #create(WindowManagerService)} instead. */
- @VisibleForTesting
- TaskPositioner(WindowManagerService service) {
- mService = service;
- }
-
- private boolean onInputEvent(InputEvent event) {
- // All returns need to be in the try block to make sure the finishInputEvent is
- // called correctly.
- if (!(event instanceof MotionEvent)
- || (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
- return false;
- }
- final MotionEvent motionEvent = (MotionEvent) event;
- if (mDragEnded) {
- // The drag has ended but the clean-up message has not been processed by
- // window manager. Drop events that occur after this until window manager
- // has a chance to clean-up the input handle.
- return true;
- }
-
- final float newX = motionEvent.getRawX();
- final float newY = motionEvent.getRawY();
-
- switch (motionEvent.getAction()) {
- case MotionEvent.ACTION_DOWN: {
- if (DEBUG_TASK_POSITIONING) {
- Slog.w(TAG, "ACTION_DOWN @ {" + newX + ", " + newY + "}");
- }
- }
- break;
-
- case MotionEvent.ACTION_MOVE: {
- if (DEBUG_TASK_POSITIONING) {
- Slog.w(TAG, "ACTION_MOVE @ {" + newX + ", " + newY + "}");
- }
- synchronized (mService.mGlobalLock) {
- mDragEnded = notifyMoveLocked(newX, newY);
- mTask.getDimBounds(mTmpRect);
- }
- if (!mTmpRect.equals(mWindowDragBounds)) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
- "wm.TaskPositioner.resizeTask");
- mService.mAtmService.resizeTask(
- mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- }
- }
- break;
-
- case MotionEvent.ACTION_UP: {
- if (DEBUG_TASK_POSITIONING) {
- Slog.w(TAG, "ACTION_UP @ {" + newX + ", " + newY + "}");
- }
- mDragEnded = true;
- }
- break;
-
- case MotionEvent.ACTION_CANCEL: {
- if (DEBUG_TASK_POSITIONING) {
- Slog.w(TAG, "ACTION_CANCEL @ {" + newX + ", " + newY + "}");
- }
- mDragEnded = true;
- }
- break;
- }
-
- if (mDragEnded) {
- final boolean wasResizing = mResizing;
- synchronized (mService.mGlobalLock) {
- endDragLocked();
- mTask.getDimBounds(mTmpRect);
- }
- if (wasResizing && !mTmpRect.equals(mWindowDragBounds)) {
- // We were using fullscreen surface during resizing. Request
- // resizeTask() one last time to restore surface to window size.
- mService.mAtmService.resizeTask(
- mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER_FORCED);
- }
-
- // Post back to WM to handle clean-ups. We still need the input
- // event handler for the last finishInputEvent()!
- mService.mTaskPositioningController.finishTaskPositioning();
- }
- return true;
- }
-
- @VisibleForTesting
- Rect getWindowDragBounds() {
- return mWindowDragBounds;
- }
-
- /**
- * @param displayContent The Display that the window being dragged is on.
- * @param win The window which will be dragged.
- */
- CompletableFuture<Void> register(DisplayContent displayContent, @NonNull WindowState win) {
- if (DEBUG_TASK_POSITIONING) {
- Slog.d(TAG, "Registering task positioner");
- }
-
- if (mClientChannel != null) {
- Slog.e(TAG, "Task positioner already registered");
- return completedFuture(null);
- }
-
- mDisplayContent = displayContent;
- mClientChannel = mService.mInputManager.createInputChannel(TAG);
-
- mInputEventReceiver = new BatchedInputEventReceiver.SimpleBatchedInputEventReceiver(
- mClientChannel, mService.mAnimationHandler.getLooper(),
- mService.mAnimator.getChoreographer(), this::onInputEvent);
-
- mDragApplicationHandle = new InputApplicationHandle(new Binder(), TAG,
- DEFAULT_DISPATCHING_TIMEOUT_MILLIS);
-
- mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
- displayContent.getDisplayId());
- mDragWindowHandle.name = TAG;
- mDragWindowHandle.token = mClientChannel.getToken();
- mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
- mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
- mDragWindowHandle.ownerPid = WindowManagerService.MY_PID;
- mDragWindowHandle.ownerUid = WindowManagerService.MY_UID;
- mDragWindowHandle.scaleFactor = 1.0f;
- // When dragging the window around, we do not want to steal focus for the window.
- mDragWindowHandle.inputConfig = InputConfig.NOT_FOCUSABLE;
-
- // The drag window cannot receive new touches.
- mDragWindowHandle.touchableRegion.setEmpty();
-
- // Pause rotations before a drag.
- ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during re-position");
- mDisplayContent.getDisplayRotation().pause();
-
- // Notify InputMonitor to take mDragWindowHandle.
- return mService.mTaskPositioningController.showInputSurface(win.getDisplayId())
- .thenRun(() -> {
- // The global lock is held by the callers of register but released before the async
- // results are waited on. We must acquire the lock in this callback to ensure thread
- // safety.
- synchronized (mService.mGlobalLock) {
- final Rect displayBounds = mTmpRect;
- displayContent.getBounds(displayBounds);
- final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
- mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
- mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics);
- mMaxVisibleSize.set(displayBounds.width(), displayBounds.height());
-
- mDragEnded = false;
-
- try {
- mClientCallback = win.mClient.asBinder();
- mClientCallback.linkToDeath(this, 0 /* flags */);
- } catch (RemoteException e) {
- // The caller has died, so clean up TaskPositioningController.
- mService.mTaskPositioningController.finishTaskPositioning();
- return;
- }
- mWindow = win;
- mTask = win.getTask();
- }
- });
- }
-
- void unregister() {
- if (DEBUG_TASK_POSITIONING) {
- Slog.d(TAG, "Unregistering task positioner");
- }
-
- if (mClientChannel == null) {
- Slog.e(TAG, "Task positioner not registered");
- return;
- }
-
- mService.mTaskPositioningController.hideInputSurface(mDisplayContent.getDisplayId());
- mService.mInputManager.removeInputChannel(mClientChannel.getToken());
-
- mInputEventReceiver.dispose();
- mInputEventReceiver = null;
- mClientChannel.dispose();
- mClientChannel = null;
-
- mDragWindowHandle = null;
- mDragApplicationHandle = null;
- mDragEnded = true;
-
- // Notify InputMonitor to remove mDragWindowHandle.
- mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
-
- // Resume rotations after a drag.
- ProtoLog.d(WM_DEBUG_ORIENTATION, "Resuming rotation after re-position");
- mDisplayContent.getDisplayRotation().resume();
- mDisplayContent = null;
- if (mClientCallback != null) {
- mClientCallback.unlinkToDeath(this, 0 /* flags */);
- }
- mWindow = null;
- }
-
- /**
- * Starts moving or resizing the task. This method should be only called from
- * {@link TaskPositioningController#startPositioningLocked} or unit tests.
- */
- void startDrag(boolean resize, boolean preserveOrientation, float startX, float startY) {
- if (DEBUG_TASK_POSITIONING) {
- Slog.d(TAG, "startDrag: win=" + mWindow + ", resize=" + resize
- + ", preserveOrientation=" + preserveOrientation + ", {" + startX + ", "
- + startY + "}");
- }
- // Use the bounds of the task which accounts for
- // multiple app windows. Don't use any bounds from win itself as it
- // may not be the same size as the task.
- final Rect startBounds = mTmpRect;
- mTask.getBounds(startBounds);
-
- mCtrlType = CTRL_NONE;
- mStartDragX = startX;
- mStartDragY = startY;
- mPreserveOrientation = preserveOrientation;
-
- if (resize) {
- if (startX < startBounds.left) {
- mCtrlType |= CTRL_LEFT;
- }
- if (startX > startBounds.right) {
- mCtrlType |= CTRL_RIGHT;
- }
- if (startY < startBounds.top) {
- mCtrlType |= CTRL_TOP;
- }
- if (startY > startBounds.bottom) {
- mCtrlType |= CTRL_BOTTOM;
- }
- mResizing = mCtrlType != CTRL_NONE;
- }
-
- // In case of !isDockedInEffect we are using the union of all task bounds. These might be
- // made up out of multiple windows which are only partially overlapping. When that happens,
- // the orientation from the window of interest to the entire stack might diverge. However
- // for now we treat them as the same.
- mStartOrientationWasLandscape = startBounds.width() >= startBounds.height();
- mWindowOriginalBounds.set(startBounds);
-
- // Notify the app that resizing has started, even though we haven't received any new
- // bounds yet. This will guarantee that the app starts the backdrop renderer before
- // configuration changes which could cause an activity restart.
- if (mResizing) {
- notifyMoveLocked(startX, startY);
-
- // The WindowPositionerEventReceiver callbacks are delivered on the same handler so this
- // initial resize is always guaranteed to happen before subsequent drag resizes.
- mService.mH.post(() -> {
- mService.mAtmService.resizeTask(
- mTask.mTaskId, startBounds, RESIZE_MODE_USER_FORCED);
- });
- }
-
- // Make sure we always have valid drag bounds even if the drag ends before any move events
- // have been handled.
- mWindowDragBounds.set(startBounds);
- }
-
- private void endDragLocked() {
- mResizing = false;
- mTask.setDragResizing(false);
- }
-
- /** Returns true if the move operation should be ended. */
- @VisibleForTesting
- boolean notifyMoveLocked(float x, float y) {
- if (DEBUG_TASK_POSITIONING) {
- Slog.d(TAG, "notifyMoveLocked: {" + x + "," + y + "}");
- }
-
- if (mCtrlType != CTRL_NONE) {
- resizeDrag(x, y);
- mTask.setDragResizing(true);
- return false;
- }
-
- // This is a moving or scrolling operation.
- // Only allow to move in stable area so the target window won't be covered by system bar.
- // Though {@link Task#resolveOverrideConfiguration} should also avoid the case.
- mDisplayContent.getStableRect(mTmpRect);
- // The task may be put in a limited display area.
- mTmpRect.intersect(mTask.getRootTask().getParent().getBounds());
-
- int nX = (int) x;
- int nY = (int) y;
- if (!mTmpRect.contains(nX, nY)) {
- // For a moving operation we allow the pointer to go out of the stack bounds, but
- // use the clamped pointer position for the drag bounds computation.
- nX = Math.min(Math.max(nX, mTmpRect.left), mTmpRect.right);
- nY = Math.min(Math.max(nY, mTmpRect.top), mTmpRect.bottom);
- }
-
- updateWindowDragBounds(nX, nY, mTmpRect);
- return false;
- }
-
- /**
- * The user is drag - resizing the window.
- *
- * @param x The x coordinate of the current drag coordinate.
- * @param y the y coordinate of the current drag coordinate.
- */
- @VisibleForTesting
- void resizeDrag(float x, float y) {
- updateDraggedBounds(TaskResizingAlgorithm.resizeDrag(x, y, mStartDragX, mStartDragY,
- mWindowOriginalBounds, mCtrlType, mMinVisibleWidth, mMinVisibleHeight,
- mMaxVisibleSize, mPreserveOrientation, mStartOrientationWasLandscape));
- }
-
- private void updateDraggedBounds(Rect newBounds) {
- mWindowDragBounds.set(newBounds);
-
- checkBoundsForOrientationViolations(mWindowDragBounds);
- }
-
- /**
- * Validate bounds against orientation violations (if DEBUG_ORIENTATION_VIOLATIONS is set).
- *
- * @param bounds The bounds to be checked.
- */
- private void checkBoundsForOrientationViolations(Rect bounds) {
- // When using debug check that we are not violating the given constraints.
- if (DEBUG_ORIENTATION_VIOLATIONS) {
- if (mStartOrientationWasLandscape != (bounds.width() >= bounds.height())) {
- Slog.e(TAG, "Orientation violation detected! should be "
- + (mStartOrientationWasLandscape ? "landscape" : "portrait")
- + " but is the other");
- } else {
- Slog.v(TAG, "new bounds size: " + bounds.width() + " x " + bounds.height());
- }
- if (mMinVisibleWidth > bounds.width() || mMinVisibleHeight > bounds.height()) {
- Slog.v(TAG, "Minimum requirement violated: Width(min, is)=(" + mMinVisibleWidth
- + ", " + bounds.width() + ") Height(min,is)=("
- + mMinVisibleHeight + ", " + bounds.height() + ")");
- }
- if (mMaxVisibleSize.x < bounds.width() || mMaxVisibleSize.y < bounds.height()) {
- Slog.v(TAG, "Maximum requirement violated: Width(min, is)=(" + mMaxVisibleSize.x
- + ", " + bounds.width() + ") Height(min,is)=("
- + mMaxVisibleSize.y + ", " + bounds.height() + ")");
- }
- }
- }
-
- private void updateWindowDragBounds(int x, int y, Rect rootTaskBounds) {
- final int offsetX = Math.round(x - mStartDragX);
- final int offsetY = Math.round(y - mStartDragY);
- mWindowDragBounds.set(mWindowOriginalBounds);
- // Horizontally, at least mMinVisibleWidth pixels of the window should remain visible.
- final int maxLeft = rootTaskBounds.right - mMinVisibleWidth;
- final int minLeft = rootTaskBounds.left + mMinVisibleWidth - mWindowOriginalBounds.width();
-
- // Vertically, the top mMinVisibleHeight of the window should remain visible.
- // (This assumes that the window caption bar is at the top of the window).
- final int minTop = rootTaskBounds.top;
- final int maxTop = rootTaskBounds.bottom - mMinVisibleHeight;
-
- mWindowDragBounds.offsetTo(
- Math.min(Math.max(mWindowOriginalBounds.left + offsetX, minLeft), maxLeft),
- Math.min(Math.max(mWindowOriginalBounds.top + offsetY, minTop), maxTop));
-
- if (DEBUG_TASK_POSITIONING) Slog.d(TAG,
- "updateWindowDragBounds: " + mWindowDragBounds);
- }
-
- public String toShortString() {
- return TAG;
- }
-
- static void setFactory(Factory factory) {
- sFactory = factory;
- }
-
- static TaskPositioner create(WindowManagerService service) {
- if (sFactory == null) {
- sFactory = new Factory() {};
- }
-
- return sFactory.create(service);
- }
-
- @Override
- public void binderDied() {
- mService.mTaskPositioningController.finishTaskPositioning();
- }
-
- interface Factory {
- default TaskPositioner create(WindowManagerService service) {
- return new TaskPositioner(service);
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
deleted file mode 100644
index 6f548ab..0000000
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import static java.util.concurrent.CompletableFuture.completedFuture;
-
-import android.annotation.Nullable;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.util.Slog;
-import android.view.Display;
-import android.view.IWindow;
-import android.view.InputWindowHandle;
-import android.view.SurfaceControl;
-
-import java.util.concurrent.CompletableFuture;
-
-/**
- * Controller for task positioning by drag.
- */
-class TaskPositioningController {
- private final WindowManagerService mService;
- private SurfaceControl mInputSurface;
- private DisplayContent mPositioningDisplay;
-
- private @Nullable TaskPositioner mTaskPositioner;
-
- private final Rect mTmpClipRect = new Rect();
-
- boolean isPositioningLocked() {
- return mTaskPositioner != null;
- }
-
- final SurfaceControl.Transaction mTransaction;
-
- InputWindowHandle getDragWindowHandleLocked() {
- return mTaskPositioner != null ? mTaskPositioner.mDragWindowHandle : null;
- }
-
- TaskPositioningController(WindowManagerService service) {
- mService = service;
- mTransaction = service.mTransactionFactory.get();
- }
-
- void hideInputSurface(int displayId) {
- if (mPositioningDisplay != null && mPositioningDisplay.getDisplayId() == displayId
- && mInputSurface != null) {
- mTransaction.hide(mInputSurface).apply();
- }
- }
-
- /**
- * @return a future that completes after window info is sent.
- */
- CompletableFuture<Void> showInputSurface(int displayId) {
- if (mPositioningDisplay == null || mPositioningDisplay.getDisplayId() != displayId) {
- return completedFuture(null);
- }
- final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
- if (mInputSurface == null) {
- mInputSurface = mService.makeSurfaceBuilder(dc.getSession())
- .setContainerLayer()
- .setName("Drag and Drop Input Consumer")
- .setCallsite("TaskPositioningController.showInputSurface")
- .setParent(dc.getOverlayLayer())
- .build();
- }
-
- final InputWindowHandle h = getDragWindowHandleLocked();
- if (h == null) {
- Slog.w(TAG_WM, "Drag is in progress but there is no "
- + "drag window handle.");
- return completedFuture(null);
- }
-
- final Display display = dc.getDisplay();
- final Point p = new Point();
- display.getRealSize(p);
- mTmpClipRect.set(0, 0, p.x, p.y);
-
- CompletableFuture<Void> result = new CompletableFuture<>();
- mTransaction.show(mInputSurface)
- .setInputWindowInfo(mInputSurface, h)
- .setLayer(mInputSurface, Integer.MAX_VALUE)
- .setPosition(mInputSurface, 0, 0)
- .setCrop(mInputSurface, mTmpClipRect)
- .addWindowInfosReportedListener(() -> result.complete(null))
- .apply();
- return result;
- }
-
- boolean startMovingTask(IWindow window, float startX, float startY) {
- WindowState win = null;
- CompletableFuture<Boolean> startPositioningLockedFuture;
- synchronized (mService.mGlobalLock) {
- win = mService.windowForClientLocked(null, window, false);
- startPositioningLockedFuture =
- startPositioningLocked(
- win, false /*resize*/, false /*preserveOrientation*/, startX, startY);
- }
-
- try {
- if (!startPositioningLockedFuture.get()) {
- return false;
- }
- } catch (Exception exception) {
- Slog.e(TAG_WM, "Exception thrown while waiting for startPositionLocked future",
- exception);
- return false;
- }
-
- synchronized (mService.mGlobalLock) {
- mService.mAtmService.setFocusedTask(win.getTask().mTaskId);
- }
- return true;
- }
-
- void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
- mService.mH.post(() -> {
- Task task;
- CompletableFuture<Boolean> startPositioningLockedFuture;
- synchronized (mService.mGlobalLock) {
- task = displayContent.findTaskForResizePoint(x, y);
- if (task == null || !task.isResizeable()) {
- // The task is not resizable, so don't do anything when the user drags the
- // the resize handles.
- return;
- }
- startPositioningLockedFuture =
- startPositioningLocked(task.getTopVisibleAppMainWindow(), true /*resize*/,
- task.preserveOrientationOnResize(), x, y);
- }
-
- try {
- if (!startPositioningLockedFuture.get()) {
- return;
- }
- } catch (Exception exception) {
- Slog.e(TAG_WM, "Exception thrown while waiting for startPositionLocked future",
- exception);
- return;
- }
-
- synchronized (mService.mGlobalLock) {
- mService.mAtmService.setFocusedTask(task.mTaskId);
- }
- });
- }
-
- private CompletableFuture<Boolean> startPositioningLocked(WindowState win, boolean resize,
- boolean preserveOrientation, float startX, float startY) {
- if (DEBUG_TASK_POSITIONING)
- Slog.d(TAG_WM, "startPositioningLocked: "
- + "win=" + win + ", resize=" + resize + ", preserveOrientation="
- + preserveOrientation + ", {" + startX + ", " + startY + "}");
-
- if (win == null || win.mActivityRecord == null) {
- Slog.w(TAG_WM, "startPositioningLocked: Bad window " + win);
- return completedFuture(false);
- }
- if (win.mInputChannel == null) {
- Slog.wtf(TAG_WM, "startPositioningLocked: " + win + " has no input channel, "
- + " probably being removed");
- return completedFuture(false);
- }
-
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent == null) {
- Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win);
- return completedFuture(false);
- }
- mPositioningDisplay = displayContent;
-
- mTaskPositioner = TaskPositioner.create(mService);
- return mTaskPositioner.register(displayContent, win).thenApply(unused -> {
- // The global lock is held by the callers of startPositioningLocked but released before
- // the async results are waited on. We must acquire the lock in this callback to ensure
- // thread safety.
- synchronized (mService.mGlobalLock) {
- // We need to grab the touch focus so that the touch events during the
- // resizing/scrolling are not sent to the app. 'win' is the main window
- // of the app, it may not have focus since there might be other windows
- // on top (eg. a dialog window).
- WindowState transferTouchFromWin = win;
- if (displayContent.mCurrentFocus != null && displayContent.mCurrentFocus != win
- && displayContent.mCurrentFocus.mActivityRecord == win.mActivityRecord) {
- transferTouchFromWin = displayContent.mCurrentFocus;
- }
- if (!mService.mInputManager.transferTouchGesture(
- transferTouchFromWin.mInputChannel.getToken(),
- mTaskPositioner.mClientChannel.getToken())) {
- Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
- cleanUpTaskPositioner();
- return false;
- }
-
- mTaskPositioner.startDrag(resize, preserveOrientation, startX, startY);
- return true;
- }
- });
- }
-
- public void finishTaskPositioning(IWindow window) {
- if (mTaskPositioner != null && mTaskPositioner.mClientCallback == window.asBinder()) {
- finishTaskPositioning();
- }
- }
-
- void finishTaskPositioning() {
- // TaskPositioner attaches the InputEventReceiver to the animation thread. We need to
- // dispose the receiver on the same thread to avoid race conditions.
- mService.mAnimationHandler.post(() -> {
- if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishPositioning");
-
- synchronized (mService.mGlobalLock) {
- cleanUpTaskPositioner();
- mPositioningDisplay = null;
- }
- });
- }
-
- private void cleanUpTaskPositioner() {
- final TaskPositioner positioner = mTaskPositioner;
- if (positioner == null) {
- return;
- }
-
- // We need to assign task positioner to null first to indicate that we're finishing task
- // positioning.
- mTaskPositioner = null;
- positioner.unregister();
- }
-}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index f6a68d5..65bc9a2 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -745,6 +745,7 @@
if (mController.isAnimating()) {
dc.enableHighPerfTransition(true);
}
+ mController.dispatchLegacyAppTransitionPending(dc.mDisplayId);
}
/**
@@ -1618,7 +1619,7 @@
mController.mTransitionTracer.logAbortedTransition(this);
// Syncengine abort will call through to onTransactionReady()
mSyncEngine.abort(mSyncId);
- mController.dispatchLegacyAppTransitionCancelled();
+ mController.dispatchLegacyAppTransitionCancelled(mTargetDisplays);
invokeTransitionEndedListeners();
}
@@ -1766,7 +1767,19 @@
}
for (int i = 0; i < mTargets.size(); ++i) {
- final DisplayArea da = mTargets.get(i).mContainer.asDisplayArea();
+ final WindowContainer<?> wc = mTargets.get(i).mContainer;
+ final WallpaperWindowToken wp = wc.asWallpaperToken();
+ if (wp != null) {
+ // If on a rotation leash, the wallpaper token surface needs to be shown explicitly
+ // because shell only gets the leash and the wallpaper token surface is not allowed
+ // to be changed by non-transition logic until the transition is finished.
+ if (Flags.ensureWallpaperInTransitions() && wp.isVisibleRequested()
+ && wp.getFixedRotationLeash() != null) {
+ transaction.show(wp.mSurfaceControl);
+ }
+ continue;
+ }
+ final DisplayArea<?> da = wc.asDisplayArea();
if (da == null) continue;
if (da.isVisibleRequested()) {
mController.mValidateDisplayVis.remove(da);
@@ -2168,14 +2181,6 @@
&& !wallpaperIsOwnTarget(wallpaper)) {
wallpaper.setVisibleRequested(false);
}
- if (showWallpaper && Flags.ensureWallpaperInTransitions()
- && wallpaper.isVisibleRequested()
- && getLeashSurface(wallpaper, t) != wallpaper.getSurfaceControl()) {
- // If on a rotation leash, we need to explicitly show the wallpaper surface
- // because shell only gets the leash and we don't allow non-transition logic
- // to touch the surfaces until the transition is over.
- t.show(wallpaper.getSurfaceControl());
- }
}
}
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index f4ff404..1df251c 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -42,6 +42,7 @@
import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import android.view.Display;
import android.view.WindowManager;
import android.window.ITransitionMetricsReporter;
import android.window.ITransitionPlayer;
@@ -326,7 +327,6 @@
mCollectingTransition.startCollecting(timeoutMs);
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Start collecting in Transition: %s",
mCollectingTransition);
- dispatchLegacyAppTransitionPending();
}
void registerTransitionPlayer(@Nullable ITransitionPlayer player,
@@ -1347,31 +1347,54 @@
mLegacyListeners.remove(listener);
}
- void dispatchLegacyAppTransitionPending() {
+ private static boolean shouldDispatchLegacyListener(
+ WindowManagerInternal.AppTransitionListener listener, int displayId) {
+ // INVALID_DISPLAY means that it is a global listener.
+ return listener.mDisplayId == Display.INVALID_DISPLAY || listener.mDisplayId == displayId;
+ }
+
+ void dispatchLegacyAppTransitionPending(int displayId) {
for (int i = 0; i < mLegacyListeners.size(); ++i) {
- mLegacyListeners.get(i).onAppTransitionPendingLocked();
+ final WindowManagerInternal.AppTransitionListener listener = mLegacyListeners.get(i);
+ if (shouldDispatchLegacyListener(listener, displayId)) {
+ listener.onAppTransitionPendingLocked();
+ }
}
}
void dispatchLegacyAppTransitionStarting(TransitionInfo info, long statusBarTransitionDelay) {
+ final long now = SystemClock.uptimeMillis();
for (int i = 0; i < mLegacyListeners.size(); ++i) {
- // TODO(shell-transitions): handle (un)occlude transition.
- mLegacyListeners.get(i).onAppTransitionStartingLocked(
- SystemClock.uptimeMillis() + statusBarTransitionDelay,
- AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
+ final WindowManagerInternal.AppTransitionListener listener = mLegacyListeners.get(i);
+ for (int j = 0; j < info.getRootCount(); ++j) {
+ final int displayId = info.getRoot(j).getDisplayId();
+ if (shouldDispatchLegacyListener(listener, displayId)) {
+ listener.onAppTransitionStartingLocked(
+ now + statusBarTransitionDelay,
+ AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
+ }
+ }
}
}
void dispatchLegacyAppTransitionFinished(ActivityRecord ar) {
for (int i = 0; i < mLegacyListeners.size(); ++i) {
- mLegacyListeners.get(i).onAppTransitionFinishedLocked(ar.token);
+ final WindowManagerInternal.AppTransitionListener listener = mLegacyListeners.get(i);
+ if (shouldDispatchLegacyListener(listener, ar.getDisplayId())) {
+ listener.onAppTransitionFinishedLocked(ar.token);
+ }
}
}
- void dispatchLegacyAppTransitionCancelled() {
- for (int i = 0; i < mLegacyListeners.size(); ++i) {
- mLegacyListeners.get(i).onAppTransitionCancelledLocked(
- false /* keyguardGoingAwayCancelled */);
+ void dispatchLegacyAppTransitionCancelled(ArrayList<DisplayContent> targetDisplays) {
+ for (int i = 0; i < targetDisplays.size(); ++i) {
+ final int displayId = targetDisplays.get(i).mDisplayId;
+ for (int j = 0; j < mLegacyListeners.size(); ++j) {
+ final var listener = mLegacyListeners.get(j);
+ if (shouldDispatchLegacyListener(listener, displayId)) {
+ listener.onAppTransitionCancelledLocked(false /* keyguardGoingAwayCancelled */);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 42b556f..6125360 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -47,7 +47,6 @@
static final boolean DEBUG_LAYOUT_REPEATS = false;
static final boolean DEBUG_WINDOW_TRACE = false;
static final boolean DEBUG_TASK_MOVEMENT = false;
- static final boolean DEBUG_TASK_POSITIONING = false;
static final boolean DEBUG_ROOT_TASK = false;
static final boolean DEBUG_DISPLAY = false;
static final boolean DEBUG_POWER = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 2ea1cf8..132e1ee 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -244,6 +244,22 @@
public static abstract class AppTransitionListener {
/**
+ * The display this listener is interested in. If it is INVALID_DISPLAY, then which display
+ * should be notified depends on the dispatcher.
+ */
+ public final int mDisplayId;
+
+ /** Let transition controller decide which display should receive the callbacks. */
+ public AppTransitionListener() {
+ this(Display.INVALID_DISPLAY);
+ }
+
+ /** It will listen the transition on the given display. */
+ public AppTransitionListener(int displayId) {
+ mDisplayId = displayId;
+ }
+
+ /**
* Called when an app transition is being setup and about to be executed.
*/
public void onAppTransitionPendingLocked() {}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index acd8b3f..f65eea0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -54,7 +54,6 @@
import static android.view.ContentRecordingSession.RECORD_CONTENT_TASK;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
-import static android.view.flags.Flags.sensitiveContentAppProtection;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
@@ -97,6 +96,7 @@
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_MULTIPLIER;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN;
+import static android.view.flags.Flags.sensitiveContentAppProtection;
import static android.window.WindowProviderService.isWindowProviderService;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
@@ -1070,7 +1070,6 @@
/** Whether or not a layout can cause a wake up when theater mode is enabled. */
boolean mAllowTheaterModeWakeFromLayout;
- final TaskPositioningController mTaskPositioningController;
final DragDropController mDragDropController;
/** For frozen screen animations. */
@@ -1428,7 +1427,6 @@
mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
- mTaskPositioningController = new TaskPositioningController(this);
mDragDropController = new DragDropController(this, mH.getLooper());
mHighRefreshRateDenylist = HighRefreshRateDenylist.create(context.getResources());
@@ -9379,40 +9377,82 @@
}
/**
- * Move focus to the adjacent embedded activity if the adjacent activity is more recently
- * created or has a window more recently added.
+ * Returns the Activity that has the most recently created window in the adjacent activities
+ * if any.
*/
- boolean moveFocusToAdjacentEmbeddedWindow(@NonNull WindowState focusedWindow) {
- final TaskFragment taskFragment = focusedWindow.getTaskFragment();
+ @NonNull
+ ActivityRecord getMostRecentActivityInAdjacent(@NonNull ActivityRecord focusedActivity) {
+ final TaskFragment taskFragment = focusedActivity.getTaskFragment();
if (taskFragment == null) {
- // Skip if not an Activity window.
- return false;
+ // Return if activity no attached.
+ return focusedActivity;
}
if (!Flags.embeddedActivityBackNavFlag()) {
- // Skip if flag is not enabled.
- return false;
+ // Return if flag is not enabled.
+ return focusedActivity;
}
- if (!focusedWindow.mActivityRecord.isEmbedded()) {
- // Skip if the focused activity is not embedded
- return false;
+ if (!focusedActivity.isEmbedded()) {
+ // Return if the focused activity is not embedded.
+ return focusedActivity;
}
final TaskFragment adjacentTaskFragment = taskFragment.getAdjacentTaskFragment();
final ActivityRecord adjacentTopActivity =
adjacentTaskFragment != null ? adjacentTaskFragment.topRunningActivity() : null;
if (adjacentTopActivity == null) {
- return false;
+ // Return if no adjacent activity.
+ return focusedActivity;
}
if (adjacentTopActivity.getLastWindowCreateTime()
- < focusedWindow.mActivityRecord.getLastWindowCreateTime()) {
- // Skip if the current focus activity has more recently active window.
+ < focusedActivity.getLastWindowCreateTime()) {
+ // Return if the current focus activity has more recently active window.
+ return focusedActivity;
+ }
+
+ return adjacentTopActivity;
+ }
+
+ @NonNull
+ WindowState getMostRecentUsedEmbeddedWindowForBack(@NonNull WindowState focusedWindow) {
+ final ActivityRecord focusedActivity = focusedWindow.getActivityRecord();
+ if (focusedActivity == null) {
+ // Not an Activity.
+ return focusedWindow;
+ }
+
+ final ActivityRecord mostRecentActivityInAdjacent = getMostRecentActivityInAdjacent(
+ focusedActivity);
+ if (mostRecentActivityInAdjacent == focusedActivity) {
+ // Already be the most recent window.
+ return focusedWindow;
+ }
+
+ // Looks for a candidate focused window on the adjacent Activity for the back event.
+ final WindowState candidate =
+ mostRecentActivityInAdjacent.getDisplayContent().findFocusedWindow(
+ mostRecentActivityInAdjacent);
+ return candidate != null ? candidate : focusedWindow;
+ }
+
+ /**
+ * Move focus to the adjacent embedded activity if the adjacent activity is more recently
+ * created or has a window more recently added.
+ * <p>
+ * Returns {@code true} if the focused window is changed. Otherwise, returns {@code false}.
+ */
+ boolean moveFocusToAdjacentEmbeddedWindow(@NonNull WindowState focusedWindow) {
+ final ActivityRecord activity = focusedWindow.getActivityRecord();
+ if (activity == null) {
return false;
}
- moveFocusToActivity(adjacentTopActivity);
+ final ActivityRecord mostRecentActivityInAdjacent = getMostRecentActivityInAdjacent(
+ activity);
+
+ moveFocusToActivity(mostRecentActivityInAdjacent);
return !focusedWindow.isFocused();
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 12c5073..984caf1 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -1674,6 +1674,22 @@
// Otherwise if other places send wpc.getConfiguration() to client, the configuration may
// be ignored due to the seq is older.
resolvedConfig.seq = newParentConfig.seq;
+
+ if (mConfigActivityRecord != null) {
+ // Let the activity decide whether to apply the size override.
+ return;
+ }
+ final DisplayContent displayContent = mAtm.mWindowManager != null
+ ? mAtm.mWindowManager.getDefaultDisplayContentLocked()
+ : null;
+ applySizeOverrideIfNeeded(
+ displayContent,
+ mInfo,
+ newParentConfig,
+ resolvedConfig,
+ false /* optsOutEdgeToEdge */,
+ false /* hasFixedRotationTransform */,
+ false /* hasCompatDisplayInsets */);
}
void dispatchConfiguration(@NonNull Configuration config) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index db4b171..9e8811f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -153,6 +153,7 @@
import com.android.server.contextualsearch.ContextualSearchManagerService;
import com.android.server.coverage.CoverageService;
import com.android.server.cpu.CpuMonitorService;
+import com.android.server.crashrecovery.CrashRecoveryModule;
import com.android.server.credentials.CredentialManagerService;
import com.android.server.criticalevents.CriticalEventLog;
import com.android.server.devicepolicy.DevicePolicyManagerService;
@@ -381,8 +382,6 @@
+ "OnDevicePersonalizationSystemService$Lifecycle";
private static final String UPDATABLE_DEVICE_CONFIG_SERVICE_CLASS =
"com.android.server.deviceconfig.DeviceConfigInit$Lifecycle";
- private static final String CRASHRECOVERY_MODULE_LIFECYCLE_CLASS =
- "com.android.server.crashrecovery.CrashRecoveryModule$Lifecycle";
/*
@@ -2939,7 +2938,7 @@
if (Flags.refactorCrashrecovery()) {
t.traceBegin("StartCrashRecoveryModule");
- mSystemServiceManager.startService(CRASHRECOVERY_MODULE_LIFECYCLE_CLASS);
+ mSystemServiceManager.startService(CrashRecoveryModule.Lifecycle.class);
t.traceEnd();
} else {
if (Flags.recoverabilityDetection()) {
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 3ed6ad7..acdbbde 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -398,13 +398,13 @@
if (randomNum >= traceFrequency) {
return;
}
- // For a small percentage a traces, we collect the initialization behavior.
- boolean traceInitialization = ThreadLocalRandom.current().nextInt(10) < 1;
- int traceDelay = traceInitialization ? 0 : 1000;
- String traceTag = traceInitialization ? "camera_init" : "camera";
+ final int traceDelay = 1000;
+ final int traceDuration = 5000;
+ final String traceTag = "camera";
BackgroundThread.get().getThreadHandler().postDelayed(() -> {
try {
- mIProfcollect.trace_process(traceTag, "android.hardware.camera.provider");
+ mIProfcollect.trace_process(traceTag, "android.hardware.camera.provider",
+ traceDuration);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage());
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java
index 644ae47..005ceee 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CpuPowerStatsCollectorValidationTest.java
@@ -130,7 +130,7 @@
boolean inCpuSection = false;
for (int i = 0; i < lines.length; i++) {
if (!inCpuSection) {
- if (lines[i].startsWith("CpuPowerStatsCollector")) {
+ if (lines[i].startsWith("cpu (1)")) {
inCpuSection = true;
}
} else if (lines[i].startsWith(" ")) {
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/CustomEnergyConsumerPowerStatsTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/CustomEnergyConsumerPowerStatsTest.java
index 7bec13f6..1621d47d 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/CustomEnergyConsumerPowerStatsTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/CustomEnergyConsumerPowerStatsTest.java
@@ -149,9 +149,9 @@
.isEqualTo(20000);
assertThat(ps2.uidStats.size()).isEqualTo(2);
assertThat(POWER_STATS_LAYOUT.getUidConsumedEnergy(ps2.uidStats.get(APP_UID1), 0))
- .isEqualTo(14000);
+ .isEqualTo(4000);
assertThat(POWER_STATS_LAYOUT.getUidConsumedEnergy(ps2.uidStats.get(APP_UID2), 0))
- .isEqualTo(21000);
+ .isEqualTo(6000);
}
@Test
@@ -209,8 +209,8 @@
assertThat(POWER_STATS_LAYOUT.getDevicePowerEstimate(deviceStats))
.isWithin(PRECISION).of(expectedPower * 0.75);
- // UID1: estimated power = 14,000 uC = 0.00388 mAh
- expectedPower = 0.00388;
+ // UID1: estimated power = 4,000 uC = 0.00111 mAh
+ expectedPower = 0.00111;
ps2.getUidStats(uidStats, APP_UID1,
states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_FOREGROUND));
assertThat(POWER_STATS_LAYOUT.getUidPowerEstimate(uidStats))
@@ -221,8 +221,8 @@
assertThat(POWER_STATS_LAYOUT.getUidPowerEstimate(uidStats))
.isWithin(PRECISION).of(expectedPower * 0.75);
- // UID2: estimated power = 21,000 uC = 0.00583 mAh
- expectedPower = 0.00583;
+ // UID2: estimated power = 6,000 uC = 0.00166 mAh
+ expectedPower = 0.00167;
ps2.getUidStats(uidStats, APP_UID2,
states(POWER_STATE_OTHER, SCREEN_STATE_ON, PROCESS_STATE_CACHED));
assertThat(POWER_STATS_LAYOUT.getUidPowerEstimate(uidStats))
diff --git a/services/tests/servicestests/src/com/android/server/autofill/HelperTest.java b/services/tests/servicestests/src/com/android/server/autofill/HelperTest.java
new file mode 100644
index 0000000..f698bea
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/autofill/HelperTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.autofill;
+
+import static com.android.server.autofill.Helper.SaveInfoStats;
+import static com.android.server.autofill.Helper.getSaveInfoStatsFromFillResponses;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Bundle;
+import android.service.autofill.FillResponse;
+import android.service.autofill.SaveInfo;
+import android.util.SparseArray;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class HelperTest {
+
+ @Test
+ public void testGetSaveInfoStatsFromFillResponses_nullFillResponses() {
+ SaveInfoStats saveInfoStats = getSaveInfoStatsFromFillResponses(null);
+
+ assertThat(saveInfoStats.saveInfoCount).isEqualTo(-1);
+ assertThat(saveInfoStats.saveDataTypeCount).isEqualTo(-1);
+ }
+
+ @Test
+ public void testGetSaveInfoStatsFromFillResponses_emptyFillResponseSparseArray() {
+ SaveInfoStats saveInfoStats = getSaveInfoStatsFromFillResponses(new SparseArray<>());
+
+ assertThat(saveInfoStats.saveInfoCount).isEqualTo(0);
+ assertThat(saveInfoStats.saveDataTypeCount).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetSaveInfoStatsFromFillResponses_singleResponseWithoutSaveInfo() {
+ FillResponse.Builder fillResponseBuilder = new FillResponse.Builder();
+ // Add client state to satisfy the sanity check in FillResponseBuilder.build()
+ Bundle clientState = new Bundle();
+ fillResponseBuilder.setClientState(clientState);
+ FillResponse testFillResponse = fillResponseBuilder.build();
+
+ SparseArray<FillResponse> testFillResponses = new SparseArray<>();
+ testFillResponses.put(0, testFillResponse);
+
+ SaveInfoStats saveInfoStats = getSaveInfoStatsFromFillResponses(testFillResponses);
+
+ assertThat(saveInfoStats.saveInfoCount).isEqualTo(0);
+ assertThat(saveInfoStats.saveDataTypeCount).isEqualTo(0);
+ }
+
+ @Test
+ public void testGetSaveInfoStatsFromFillResponses_singleResponseWithSaveInfo() {
+ FillResponse.Builder fillResponseBuilder = new FillResponse.Builder();
+ SaveInfo.Builder saveInfoBuilder = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC);
+ fillResponseBuilder.setSaveInfo(saveInfoBuilder.build());
+ FillResponse testFillResponse = fillResponseBuilder.build();
+
+ SparseArray<FillResponse> testFillResponses = new SparseArray<>();
+ testFillResponses.put(0, testFillResponse);
+
+ SaveInfoStats saveInfoStats = getSaveInfoStatsFromFillResponses(testFillResponses);
+
+ assertThat(saveInfoStats.saveInfoCount).isEqualTo(1);
+ assertThat(saveInfoStats.saveDataTypeCount).isEqualTo(1);
+ }
+
+ @Test
+ public void testGetSaveInfoStatsFromFillResponses_multipleResponseWithDifferentTypeSaveInfo() {
+ FillResponse.Builder fillResponseBuilder1 = new FillResponse.Builder();
+ SaveInfo.Builder saveInfoBuilder1 = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_GENERIC);
+ fillResponseBuilder1.setSaveInfo(saveInfoBuilder1.build());
+ FillResponse testFillResponse1 = fillResponseBuilder1.build();
+
+ FillResponse.Builder fillResponseBuilder2 = new FillResponse.Builder();
+ SaveInfo.Builder saveInfoBuilder2 = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_ADDRESS);
+ fillResponseBuilder2.setSaveInfo(saveInfoBuilder2.build());
+ FillResponse testFillResponse2 = fillResponseBuilder2.build();
+
+ FillResponse.Builder fillResponseBuilder3 = new FillResponse.Builder();
+ SaveInfo.Builder saveInfoBuilder3 = new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_ADDRESS);
+ fillResponseBuilder3.setSaveInfo(saveInfoBuilder3.build());
+ FillResponse testFillResponse3 = fillResponseBuilder3.build();
+
+ SparseArray<FillResponse> testFillResponses = new SparseArray<>();
+ testFillResponses.put(0, testFillResponse1);
+ testFillResponses.put(1, testFillResponse2);
+ testFillResponses.put(2, testFillResponse3);
+
+ SaveInfoStats saveInfoStats = getSaveInfoStatsFromFillResponses(testFillResponses);
+
+ // Save info count is 3. Since two save info share the same save data type, the distinct
+ // save data type count is 2.
+ assertThat(saveInfoStats.saveInfoCount).isEqualTo(3);
+ assertThat(saveInfoStats.saveDataTypeCount).isEqualTo(2);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index 316b5fa..689b241 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -39,6 +39,7 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -364,6 +365,39 @@
@EnableFlags(android.companion.virtualdevice.flags
.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
@Test
+ public void testReuseProjection_keyguardNotLocked_startConsentDialog()
+ throws NameNotFoundException {
+ MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
+ projection.start(mIMediaProjectionCallback);
+
+ doNothing().when(mContext).startActivityAsUser(any(), any());
+ doReturn(false).when(mKeyguardManager).isKeyguardLocked();
+
+ MediaProjectionManagerService.BinderService mediaProjectionBinderService =
+ mService.new BinderService(mContext);
+ mediaProjectionBinderService.requestConsentForInvalidProjection(projection);
+
+ verify(mContext).startActivityAsUser(any(), any());
+ }
+
+ @EnableFlags(android.companion.virtualdevice.flags
+ .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+ @Test
+ public void testReuseProjection_keyguardLocked_noConsentDialog() throws NameNotFoundException {
+ MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
+ projection.start(mIMediaProjectionCallback);
+
+ doReturn(true).when(mKeyguardManager).isKeyguardLocked();
+ MediaProjectionManagerService.BinderService mediaProjectionBinderService =
+ mService.new BinderService(mContext);
+ mediaProjectionBinderService.requestConsentForInvalidProjection(projection);
+
+ verify(mContext, never()).startActivityAsUser(any(), any());
+ }
+
+ @EnableFlags(android.companion.virtualdevice.flags
+ .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS)
+ @Test
public void testKeyguardLocked_stopsActiveProjection() throws Exception {
MediaProjectionManagerService service =
new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector);
diff --git a/services/tests/wmtests/res/xml/bookmarks.xml b/services/tests/wmtests/res/xml/bookmarks.xml
index 88419e9..1549b2d 100644
--- a/services/tests/wmtests/res/xml/bookmarks.xml
+++ b/services/tests/wmtests/res/xml/bookmarks.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2024 The Android Open Source Project
+<!-- Copyright 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.
@@ -14,6 +14,8 @@
limitations under the License.
-->
<bookmarks>
+ <!-- the key combinations for the following shortcuts must be in sync
+ with the key combinations sent by the test in ModifierShortcutTests.java -->
<bookmark
role="android.app.role.BROWSER"
shortcut="b" />
@@ -38,4 +40,37 @@
<bookmark
category="android.intent.category.APP_CALCULATOR"
shortcut="u" />
+
+ <!-- The following shortcuts will not be invoked by tests but are here to
+ provide test coverage of parsing the different types of shortcut. -->
+ <bookmark
+ package="com.test"
+ class="com.test.BookmarkTest"
+ shortcut="a" />
+ <bookmark
+ package="com.test2"
+ class="com.test.BookmarkTest"
+ shortcut="d" />
+
+ <bookmark
+ role="android.app.role.BROWSER"
+ shortcut="b"
+ shift="true" />
+ <bookmark
+ category="android.intent.category.APP_CONTACTS"
+ shortcut="c"
+ shift="true" />
+ <bookmark
+ package="com.test"
+ class="com.test.BookmarkTest"
+ shortcut="a"
+ shift="true" />
+
+ <!-- It's intended that this package/class will NOT resolve so we test the resolution
+ failure case. -->
+ <bookmark
+ package="com.test3"
+ class="com.test.BookmarkTest"
+ shortcut="f" />
+
</bookmarks>
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
index 8c375d4..5533ff9 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright 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.
@@ -19,15 +19,22 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertEquals;
+import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Handler;
@@ -58,27 +65,56 @@
private Handler mHandler;
private Context mContext;
private Resources mResources;
+ private PackageManager mPackageManager;
@Before
public void setUp() {
mHandler = new Handler(Looper.getMainLooper());
mContext = spy(getInstrumentation().getTargetContext());
mResources = spy(mContext.getResources());
+ mPackageManager = spy(mContext.getPackageManager());
XmlResourceParser testBookmarks = mResources.getXml(
com.android.frameworks.wmtests.R.xml.bookmarks);
when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mResources.getXml(R.xml.bookmarks)).thenReturn(testBookmarks);
+ try {
+ // Keep packageName / className in sync with
+ // services/tests/wmtests/res/xml/bookmarks.xml
+ ActivityInfo testActivityInfo = new ActivityInfo();
+ testActivityInfo.applicationInfo = new ApplicationInfo();
+ testActivityInfo.packageName =
+ testActivityInfo.applicationInfo.packageName = "com.test";
+
+ doReturn(testActivityInfo).when(mPackageManager).getActivityInfo(
+ eq(new ComponentName("com.test", "com.test.BookmarkTest")), anyInt());
+ doThrow(new PackageManager.NameNotFoundException("com.test3")).when(mPackageManager)
+ .getActivityInfo(eq(new ComponentName("com.test3", "com.test.BookmarkTest")),
+ anyInt());
+ } catch (PackageManager.NameNotFoundException ignored) { }
+ doReturn(new String[] { "com.test" }).when(mPackageManager)
+ .canonicalToCurrentPackageNames(aryEq(new String[] { "com.test2" }));
+
mModifierShortcutManager = new ModifierShortcutManager(mContext, mHandler);
}
@Test
public void test_getApplicationLaunchKeyboardShortcuts() {
+ // Expected values here determined by the number of shortcuts defined in
+ // services/tests/wmtests/res/xml/bookmarks.xml
+
+ // Total valid shortcuts.
KeyboardShortcutGroup group =
mModifierShortcutManager.getApplicationLaunchKeyboardShortcuts(-1);
- assertEquals(8, group.getItems().size());
+ assertEquals(13, group.getItems().size());
+
+ // Total valid shift shortcuts.
+ assertEquals(3, group.getItems().stream()
+ .filter(s -> s.getModifiers() == (KeyEvent.META_SHIFT_ON | KeyEvent.META_META_ON))
+ .count());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatAspectRatioOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatAspectRatioOverridesTest.java
new file mode 100644
index 0000000..ddd6d56
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatAspectRatioOverridesTest.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2;
+import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static org.junit.Assert.assertEquals;
+
+import android.compat.testing.PlatformCompatChangeRule;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.annotation.NonNull;
+
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
+import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+import java.util.function.Consumer;
+
+/**
+ * Test class for {@link AppCompatAspectRatioOverrides}.
+ * <p>
+ * Build/Install/Run:
+ * atest WmTests:AppCompatAspectRatioOverridesTest
+ */
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class AppCompatAspectRatioOverridesTest extends WindowTestsBase {
+
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
+ @Test
+ public void testShouldApplyUserFullscreenOverride_trueProperty_returnsFalse() {
+ runTestScenario((robot)-> {
+ robot.prop().enable(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE);
+ robot.conf().enableUserAppAspectRatioFullscreen(/* enabled */ false);
+
+ robot.activity().createActivityWithComponent();
+
+ robot.checkShouldApplyUserFullscreenOverride(/* expected */ false);
+ });
+ }
+
+ @Test
+ public void testShouldApplyUserFullscreenOverride_falseFullscreenProperty_returnsFalse() {
+ runTestScenario((robot)-> {
+ robot.conf().enableUserAppAspectRatioFullscreen(/* enabled */ true);
+ robot.activity().setIgnoreOrientationRequest(/* enabled */ true);
+ robot.prop().disable(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+ robot.activity().setGetUserMinAspectRatioOverrideCode(USER_MIN_ASPECT_RATIO_FULLSCREEN);
+
+ robot.checkShouldApplyUserFullscreenOverride(/* expected */ false);
+ });
+ }
+
+ @Test
+ public void testShouldApplyUserFullscreenOverride_falseSettingsProperty_returnsFalse() {
+ runTestScenario((robot)-> {
+ robot.conf().enableUserAppAspectRatioSettings(/* enabled */ true);
+ robot.activity().setIgnoreOrientationRequest(/* enabled */ true);
+ robot.prop().disable(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+ robot.activity().setGetUserMinAspectRatioOverrideCode(USER_MIN_ASPECT_RATIO_FULLSCREEN);
+ robot.checkShouldApplyUserFullscreenOverride(/* expected */ false);
+ });
+ }
+
+
+ @Test
+ public void testShouldApplyUserFullscreenOverride_returnsTrue() {
+ runTestScenario((robot)-> {
+ robot.conf().enableUserAppAspectRatioFullscreen(/* enabled */ true);
+ robot.activity().setIgnoreOrientationRequest(/* enabled */ true);
+ robot.activity().createActivityWithComponent();
+ robot.activity().setGetUserMinAspectRatioOverrideCode(USER_MIN_ASPECT_RATIO_FULLSCREEN);
+
+ robot.checkShouldApplyUserFullscreenOverride(/* expected */ true);
+ });
+ }
+
+ @Test
+ public void testShouldEnableUserAspectRatioSettings_falseProperty_returnsFalse() {
+ runTestScenario((robot)-> {
+ robot.conf().enableUserAppAspectRatioSettings(/* enabled */ true);
+ robot.activity().setIgnoreOrientationRequest(/* enabled */ true);
+ robot.prop().disable(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+ robot.activity().setGetUserMinAspectRatioOverrideCode(USER_MIN_ASPECT_RATIO_3_2);
+
+ robot.checkShouldEnableUserAspectRatioSettings(/* expected */ false);
+ });
+ }
+
+ @Test
+ public void testShouldEnableUserAspectRatioSettings_trueProperty_returnsTrue() {
+ runTestScenario((robot)-> {
+ robot.conf().enableUserAppAspectRatioSettings(/* enabled */ true);
+ robot.activity().setIgnoreOrientationRequest(/* enabled */ true);
+ robot.prop().enable(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+ robot.activity().setGetUserMinAspectRatioOverrideCode(USER_MIN_ASPECT_RATIO_3_2);
+
+ robot.checkShouldEnableUserAspectRatioSettings(/* expected */ true);
+ });
+ }
+
+ @Test
+ public void testShouldEnableUserAspectRatioSettings_ignoreOrientation_returnsFalse() {
+ runTestScenario((robot)-> {
+ robot.conf().enableUserAppAspectRatioSettings(/* enabled */ false);
+ robot.activity().setIgnoreOrientationRequest(/* enabled */ true);
+ robot.prop().enable(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+ robot.activity().setGetUserMinAspectRatioOverrideCode(USER_MIN_ASPECT_RATIO_3_2);
+
+ robot.checkShouldEnableUserAspectRatioSettings(/* expected */ false);
+ });
+ }
+
+ @Test
+ public void testShouldApplyUserMinAspectRatioOverride_falseProperty_returnsFalse() {
+ runTestScenario((robot)-> {
+ robot.conf().enableUserAppAspectRatioSettings(/* enabled */ true);
+ robot.activity().setIgnoreOrientationRequest(/* enabled */ true);
+ robot.prop().disable(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+ robot.activity().setGetUserMinAspectRatioOverrideCode(USER_MIN_ASPECT_RATIO_3_2);
+
+ robot.checkShouldEnableUserAspectRatioSettings(/* expected */ false);
+ });
+ }
+
+ @Test
+ public void testShouldApplyUserMinAspectRatioOverride_trueProperty_returnsFalse() {
+ runTestScenario((robot)-> {
+ robot.conf().enableUserAppAspectRatioSettings(/* enabled */ false);
+ robot.prop().enable(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+
+ robot.checkShouldEnableUserAspectRatioSettings(/* enabled */ false);
+ });
+ }
+
+ @Test
+ public void testShouldApplyUserMinAspectRatioOverride_disabledIgnoreOrientationRequest() {
+ runTestScenario((robot)-> {
+ robot.conf().enableUserAppAspectRatioSettings(/* enabled */ true);
+ robot.activity().setIgnoreOrientationRequest(/* enabled */ false);
+ robot.activity().createActivityWithComponent();
+ robot.activity().setGetUserMinAspectRatioOverrideCode(USER_MIN_ASPECT_RATIO_3_2);
+
+ robot.checkShouldApplyUserMinAspectRatioOverride(/* expected */ false);
+ });
+ }
+
+ @Test
+ public void testShouldApplyUserMinAspectRatioOverride_returnsTrue() {
+ runTestScenario((robot)-> {
+ robot.conf().enableUserAppAspectRatioSettings(/* enabled */ true);
+ robot.activity().setIgnoreOrientationRequest(/* enabled */ true);
+ robot.activity().createActivityWithComponent();
+ robot.activity().setGetUserMinAspectRatioOverrideCode(USER_MIN_ASPECT_RATIO_3_2);
+
+ robot.checkShouldApplyUserMinAspectRatioOverride(/* expected */ true);
+ });
+ }
+
+ @Test
+ public void testShouldApplyUserMinAspectRatioOverride_ignoreOrientation_returnsFalse() {
+ runTestScenario((robot)-> {
+ robot.conf().enableUserAppAspectRatioSettings(/* enabled */ false);
+ robot.activity().setIgnoreOrientationRequest(/* enabled */ true);
+ robot.activity().createActivityWithComponent();
+ robot.activity().setGetUserMinAspectRatioOverrideCode(USER_MIN_ASPECT_RATIO_3_2);
+
+ robot.checkShouldApplyUserMinAspectRatioOverride(/* expected */ false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
+ public void testShouldOverrideMinAspectRatio_overrideEnabled_returnsTrue() {
+ runTestScenario((robot)-> {
+ robot.activity().createActivityWithComponent();
+
+ robot.checkShouldOverrideMinAspectRatio(/* expected */ true);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
+ public void testShouldOverrideMinAspectRatio_propertyTrue_overrideEnabled_returnsTrue() {
+ runTestScenario((robot)-> {
+ robot.prop().enable(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+
+ robot.checkShouldOverrideMinAspectRatio(/* expected */ true);
+ });
+ }
+
+ @Test
+ @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
+ public void testShouldOverrideMinAspectRatio_propertyTrue_overrideDisabled_returnsFalse() {
+ runTestScenario((robot)-> {
+ robot.prop().enable(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+
+ robot.checkShouldOverrideMinAspectRatio(/* expected */ false);
+ });
+ }
+
+ @Test
+ @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
+ public void testShouldOverrideMinAspectRatio_overrideDisabled_returnsFalse() {
+ runTestScenario((robot)-> {
+ robot.activity().createActivityWithComponent();
+
+ robot.checkShouldOverrideMinAspectRatio(/* expected */ false);
+ });
+ }
+
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
+ public void testshouldOverrideMinAspectRatio_propertyFalse_overrideEnabled_returnsFalse() {
+ runTestScenario((robot)-> {
+ robot.prop().disable(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+
+ robot.checkShouldOverrideMinAspectRatio(/* expected */ false);
+ });
+ }
+
+ @Test
+ @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
+ public void testshouldOverrideMinAspectRatio_propertyFalse_noOverride_returnsFalse() {
+ runTestScenario((robot)-> {
+ robot.prop().disable(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+
+ robot.checkShouldOverrideMinAspectRatio(/* expected */ false);
+ });
+ }
+
+ /**
+ * Runs a test scenario providing a Robot.
+ */
+ void runTestScenario(@NonNull Consumer<AspectRatioOverridesRobotTest> consumer) {
+ spyOn(mWm.mAppCompatConfiguration);
+ final AspectRatioOverridesRobotTest robot =
+ new AspectRatioOverridesRobotTest(mWm, mAtm, mSupervisor);
+ consumer.accept(robot);
+ }
+
+ private static class AspectRatioOverridesRobotTest extends AppCompatRobotBase {
+
+ AspectRatioOverridesRobotTest(@NonNull WindowManagerService wm,
+ @NonNull ActivityTaskManagerService atm,
+ @NonNull ActivityTaskSupervisor supervisor) {
+ super(wm, atm, supervisor);
+ }
+
+ void checkShouldApplyUserFullscreenOverride(boolean expected) {
+ assertEquals(expected, getTopActivityAppCompatAspectRatioOverrides()
+ .shouldApplyUserFullscreenOverride());
+ }
+
+ void checkShouldEnableUserAspectRatioSettings(boolean expected) {
+ assertEquals(expected, getTopActivityAppCompatAspectRatioOverrides()
+ .shouldEnableUserAspectRatioSettings());
+ }
+
+ void checkShouldApplyUserMinAspectRatioOverride(boolean expected) {
+ assertEquals(expected, getTopActivityAppCompatAspectRatioOverrides()
+ .shouldApplyUserMinAspectRatioOverride());
+ }
+
+ void checkShouldOverrideMinAspectRatio(boolean expected) {
+ assertEquals(expected, getTopActivityAppCompatAspectRatioOverrides()
+ .shouldOverrideMinAspectRatio());
+ }
+
+ @NonNull
+ private AppCompatAspectRatioOverrides getTopActivityAppCompatAspectRatioOverrides() {
+ return activity().top().mAppCompatController.getAppCompatAspectRatioOverrides();
+ }
+ }
+
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
index d8c7fb3..de99f54 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
@@ -25,6 +25,7 @@
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION;
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
+import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM;
@@ -36,6 +37,7 @@
import androidx.annotation.NonNull;
+import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
import org.junit.Rule;
@@ -286,6 +288,88 @@
});
}
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
+ public void shouldOverrideMinAspectRatioForCamera_overrideEnabled_returnsTrue() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponent();
+ robot.activity().activateCameraInPolicy(/* isCameraActive */ true);
+
+ robot.checkShouldOverrideMinAspectRatioForCamera(/* expected */ true);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
+ public void shouldOverrideMinAspectRatioForCamera_propertyTrue_overrideEnabled_returnsTrue() {
+ runTestScenario((robot) -> {
+ robot.prop().enable(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+ robot.activity().activateCameraInPolicy(/* isCameraActive */ true);
+
+ robot.checkShouldOverrideMinAspectRatioForCamera(/* expected */ true);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
+ public void shouldOverrideMinAspectRatioForCamera_propertyTrue_overrideEnabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.prop().enable(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+ robot.activity().activateCameraInPolicy(/* isCameraActive */ false);
+
+ robot.checkShouldOverrideMinAspectRatioForCamera(/* expected */ false);
+ });
+ }
+
+ @Test
+ @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
+ public void shouldOverrideMinAspectRatioForCamera_propertyTrue_overrideDisabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.prop().enable(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+ robot.activity().activateCameraInPolicy(/* isCameraActive */ true);
+
+ robot.checkShouldOverrideMinAspectRatioForCamera(/* expected */ false);
+ });
+ }
+
+ @Test
+ @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
+ public void shouldOverrideMinAspectRatioForCamera_overrideDisabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponent();
+ robot.activity().activateCameraInPolicy(/* isCameraActive */ true);
+
+ robot.checkShouldOverrideMinAspectRatioForCamera(/* expected */ false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
+ public void shouldOverrideMinAspectRatioForCamera_propertyFalse_overrideEnabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.prop().disable(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+
+ robot.checkShouldOverrideMinAspectRatioForCamera(/* expected */ false);
+ });
+ }
+
+ @Test
+ @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
+ public void shouldOverrideMinAspectRatioForCamera_propertyFalse_noOverride_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.prop().disable(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ robot.activity().createActivityWithComponent();
+ robot.activity().activateCameraInPolicy(/* isCameraActive */ true);
+
+ robot.checkShouldOverrideMinAspectRatioForCamera(/* expected */ false);
+ });
+ }
+
/**
* Runs a test scenario providing a Robot.
*/
@@ -323,6 +407,11 @@
.shouldApplyFreeformTreatmentForCameraCompat(), expected);
}
+ void checkShouldOverrideMinAspectRatioForCamera(boolean expected) {
+ Assert.assertEquals(getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera(), expected);
+ }
+
void checkIsCameraActive(boolean active) {
Assert.assertEquals(getAppCompatCameraOverrides().isCameraActive(), active);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatComponentPropRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatComponentPropRobot.java
index d568eec..361177f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatComponentPropRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatComponentPropRobot.java
@@ -32,27 +32,27 @@
*/
class AppCompatComponentPropRobot {
@NonNull
- private final WindowManagerService mWm;
+ private final PackageManager mPackageManager;
AppCompatComponentPropRobot(@NonNull WindowManagerService wm) {
- mWm = wm;
+ mPackageManager = wm.mContext.getPackageManager();
+ spyOn(mPackageManager);
}
void enable(@NonNull String propertyName) {
- setPropertyValue(propertyName, /* enabled */ true);
+ setPropertyValue(propertyName, "", "", /* enabled */ true);
}
void disable(@NonNull String propertyName) {
- setPropertyValue(propertyName, /* enabled */ false);
+ setPropertyValue(propertyName, "", "", /* enabled */ false);
}
- private void setPropertyValue(@NonNull String propertyName, boolean enabled) {
+ private void setPropertyValue(@NonNull String propertyName, @NonNull String packageName,
+ @NonNull String className, boolean enabled) {
final PackageManager.Property property = new PackageManager.Property(propertyName,
- /* value */ enabled, /* packageName */ "", /* className */ "");
- final PackageManager pm = mWm.mContext.getPackageManager();
- spyOn(pm);
+ /* value */ enabled, packageName, className);
try {
- doReturn(property).when(pm).getProperty(eq(propertyName), anyString());
+ doReturn(property).when(mPackageManager).getProperty(eq(propertyName), anyString());
} catch (PackageManager.NameNotFoundException e) {
fail(e.getLocalizedMessage());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatConfigurationRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatConfigurationRobot.java
index cb3cf6b..0a1b16b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatConfigurationRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatConfigurationRobot.java
@@ -66,6 +66,4 @@
doReturn(enabled).when(mAppCompatConfiguration)
.isCameraCompatSplitScreenAspectRatioEnabled();
}
-
-
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index 63c14b9..afa22bc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -67,6 +67,7 @@
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedCallbackInfo;
import android.window.OnBackInvokedDispatcher;
+import android.window.TaskFragmentOrganizer;
import android.window.TaskSnapshot;
import android.window.WindowOnBackInvokedDispatcher;
@@ -670,25 +671,29 @@
}
@Test
- public void testAdjacentFocusInActivityEmbedding() {
+ public void testBackOnMostRecentWindowInActivityEmbedding() {
mSetFlagsRule.enableFlags(Flags.FLAG_EMBEDDED_ACTIVITY_BACK_NAV_FLAG);
final Task task = createTask(mDefaultDisplay);
- final TaskFragment primaryTf = createTaskFragmentWithActivity(task);
- final TaskFragment secondaryTf = createTaskFragmentWithActivity(task);
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final TaskFragment primaryTf = createTaskFragmentWithEmbeddedActivity(task, organizer);
+ final TaskFragment secondaryTf = createTaskFragmentWithEmbeddedActivity(task, organizer);
final ActivityRecord primaryActivity = primaryTf.getTopMostActivity();
final ActivityRecord secondaryActivity = secondaryTf.getTopMostActivity();
primaryTf.setAdjacentTaskFragment(secondaryTf);
secondaryTf.setAdjacentTaskFragment(primaryTf);
- final WindowState windowState = mock(WindowState.class);
- windowState.mActivityRecord = primaryActivity;
- doReturn(windowState).when(mWm).getFocusedWindowLocked();
- doReturn(primaryTf).when(windowState).getTaskFragment();
+ final WindowState primaryWindow = mock(WindowState.class);
+ final WindowState secondaryWindow = mock(WindowState.class);
+ doReturn(primaryActivity).when(primaryWindow).getActivityRecord();
+ doReturn(secondaryActivity).when(secondaryWindow).getActivityRecord();
doReturn(1L).when(primaryActivity).getLastWindowCreateTime();
doReturn(2L).when(secondaryActivity).getLastWindowCreateTime();
+ doReturn(mDisplayContent).when(primaryActivity).getDisplayContent();
+ doReturn(secondaryWindow).when(mDisplayContent).findFocusedWindow(eq(secondaryActivity));
- startBackNavigation();
- verify(mWm).moveFocusToActivity(eq(secondaryActivity));
+ final WindowState mostRecentUsedWindow =
+ mWm.getMostRecentUsedEmbeddedWindowForBack(primaryWindow);
+ assertThat(mostRecentUsedWindow).isEqualTo(secondaryWindow);
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index d318f00..44c7057b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -19,19 +19,12 @@
import static android.content.pm.ActivityInfo.FORCE_NON_RESIZE_APP;
import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO;
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
-import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_3_2;
-import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE;
-import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -119,8 +112,6 @@
mController = new LetterboxUiController(mWm, mActivity);
}
-
-
@Test
public void testGetCropBoundsIfNeeded_handleCropForTransparentActivityBasedOnOpaqueBounds() {
final InsetsSource taskbar = new InsetsSource(/*id=*/ 0,
@@ -320,164 +311,6 @@
return mainWindow;
}
- // shouldApplyUser...Override
- @Test
- public void testShouldApplyUserFullscreenOverride_trueProperty_returnsFalse() throws Exception {
- mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE,
- /* value */ true);
-
- doReturn(false).when(mAppCompatConfiguration).isUserAppAspectRatioFullscreenEnabled();
- mActivity = setUpActivityWithComponent();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldApplyUserFullscreenOverride());
- }
-
- @Test
- public void testShouldApplyUserFullscreenOverride_falseFullscreenProperty_returnsFalse()
- throws Exception {
- prepareActivityThatShouldApplyUserFullscreenOverride();
- mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE,
- /* value */ false);
-
- mActivity = setUpActivityWithComponent();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldApplyUserFullscreenOverride());
- }
-
- @Test
- public void testShouldApplyUserFullscreenOverride_falseSettingsProperty_returnsFalse()
- throws Exception {
- prepareActivityThatShouldApplyUserFullscreenOverride();
- mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, /* value */ false);
-
- mActivity = setUpActivityWithComponent();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldApplyUserFullscreenOverride());
- }
-
- @Test
- public void testShouldApplyUserFullscreenOverride_returnsTrue() {
- prepareActivityThatShouldApplyUserFullscreenOverride();
-
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldApplyUserFullscreenOverride());
- }
-
- @Test
- public void testShouldEnableUserAspectRatioSettings_falseProperty_returnsFalse()
- throws Exception {
- prepareActivityThatShouldApplyUserMinAspectRatioOverride();
- mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, /* value */ false);
-
- mActivity = setUpActivityWithComponent();
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldEnableUserAspectRatioSettings());
- }
-
- @Test
- public void testShouldEnableUserAspectRatioSettings_trueProperty_returnsTrue()
- throws Exception {
-
- mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, /* value */ true);
- mActivity = setUpActivityWithComponent();
- prepareActivityThatShouldApplyUserMinAspectRatioOverride();
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldEnableUserAspectRatioSettings());
- }
-
- @Test
- public void testShouldEnableUserAspectRatioSettings_noIgnoreOrientation_returnsFalse()
- throws Exception {
- prepareActivityForShouldApplyUserMinAspectRatioOverride(/* orientationRequest */ false);
- mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, /* value */ true);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldEnableUserAspectRatioSettings());
- }
-
- @Test
- public void testShouldApplyUserMinAspectRatioOverride_falseProperty_returnsFalse()
- throws Exception {
- prepareActivityThatShouldApplyUserMinAspectRatioOverride();
- mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, /* value */ false);
-
- mActivity = setUpActivityWithComponent();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldEnableUserAspectRatioSettings());
- }
-
- @Test
- public void testShouldApplyUserMinAspectRatioOverride_trueProperty_returnsFalse()
- throws Exception {
- doReturn(false).when(mAppCompatConfiguration).isUserAppAspectRatioSettingsEnabled();
- mockThatProperty(PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE, /* value */ true);
-
- mActivity = setUpActivityWithComponent();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldApplyUserMinAspectRatioOverride());
- }
-
- @Test
- public void testShouldApplyUserMinAspectRatioOverride_disabledIgnoreOrientationRequest() {
- prepareActivityThatShouldApplyUserMinAspectRatioOverride();
- mDisplayContent.setIgnoreOrientationRequest(false);
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldApplyUserMinAspectRatioOverride());
- }
-
- @Test
- public void testShouldApplyUserMinAspectRatioOverride_returnsTrue() {
- prepareActivityThatShouldApplyUserMinAspectRatioOverride();
-
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldApplyUserMinAspectRatioOverride());
- }
-
- @Test
- public void testShouldApplyUserMinAspectRatioOverride_noIgnoreOrientation_returnsFalse() {
- prepareActivityForShouldApplyUserMinAspectRatioOverride(/* orientationRequest */ false);
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldApplyUserMinAspectRatioOverride());
- }
-
- private void prepareActivityForShouldApplyUserMinAspectRatioOverride(
- boolean orientationRequest) {
- spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
- doReturn(orientationRequest).when(
- mAppCompatConfiguration).isUserAppAspectRatioSettingsEnabled();
- mDisplayContent.setIgnoreOrientationRequest(true);
- doReturn(USER_MIN_ASPECT_RATIO_3_2)
- .when(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
- .getUserMinAspectRatioOverrideCode();
- }
-
- private void prepareActivityThatShouldApplyUserMinAspectRatioOverride() {
- prepareActivityForShouldApplyUserMinAspectRatioOverride(/* orientationRequest */ true);
- }
-
- private void prepareActivityThatShouldApplyUserFullscreenOverride() {
- spyOn(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides());
- doReturn(true).when(mAppCompatConfiguration).isUserAppAspectRatioFullscreenEnabled();
- mDisplayContent.setIgnoreOrientationRequest(true);
- doReturn(USER_MIN_ASPECT_RATIO_FULLSCREEN)
- .when(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides())
- .getUserMinAspectRatioOverrideCode();
- }
-
// shouldUseDisplayLandscapeNaturalOrientation
@Test
@@ -595,156 +428,6 @@
}
@Test
- @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
- public void testshouldOverrideMinAspectRatio_overrideEnabled_returnsTrue() {
- mActivity = setUpActivityWithComponent();
-
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldOverrideMinAspectRatio());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
- public void testshouldOverrideMinAspectRatio_propertyTrue_overrideEnabled_returnsTrue()
- throws Exception {
- mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
- mActivity = setUpActivityWithComponent();
-
- assertTrue(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldOverrideMinAspectRatio());
- }
-
- @Test
- @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
- public void testshouldOverrideMinAspectRatio_propertyTrue_overrideDisabled_returnsFalse()
- throws Exception {
- mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
- mActivity = setUpActivityWithComponent();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldOverrideMinAspectRatio());
- }
-
- @Test
- @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
- public void testshouldOverrideMinAspectRatio_overrideDisabled_returnsFalse() {
- mActivity = setUpActivityWithComponent();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldOverrideMinAspectRatio());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
- public void testshouldOverrideMinAspectRatio_propertyFalse_overrideEnabled_returnsFalse()
- throws Exception {
- mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ false);
-
- mActivity = setUpActivityWithComponent();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldOverrideMinAspectRatio());
- }
-
- @Test
- @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO})
- public void testshouldOverrideMinAspectRatio_propertyFalse_noOverride_returnsFalse()
- throws Exception {
- mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ false);
- mActivity = setUpActivityWithComponent();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatAspectRatioOverrides()
- .shouldOverrideMinAspectRatio());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
- public void shouldOverrideMinAspectRatioForCamera_overrideEnabled_returnsTrue() {
- mActivity = setUpActivityWithComponent();
- doReturn(true).when(mActivity.mAppCompatController
- .getAppCompatCameraOverrides()).isCameraActive();
-
- assertTrue(mActivity.mAppCompatController.getAppCompatCameraOverrides()
- .shouldOverrideMinAspectRatioForCamera());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
- public void shouldOverrideMinAspectRatioForCamera_propertyTrue_overrideEnabled_returnsTrue()
- throws Exception {
- mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
- mActivity = setUpActivityWithComponent();
- doReturn(true).when(mActivity.mAppCompatController
- .getAppCompatCameraOverrides()).isCameraActive();
-
- assertTrue(mActivity.mAppCompatController.getAppCompatCameraOverrides()
- .shouldOverrideMinAspectRatioForCamera());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
- public void shouldOverrideMinAspectRatioForCamera_propertyTrue_overrideEnabled_returnsFalse()
- throws Exception {
- mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
- mActivity = setUpActivityWithComponent();
- doReturn(false).when(mActivity.mAppCompatController
- .getAppCompatCameraOverrides()).isCameraActive();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
- .shouldOverrideMinAspectRatioForCamera());
- }
-
- @Test
- @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
- public void shouldOverrideMinAspectRatioForCamera_propertyTrue_overrideDisabled_returnsFalse()
- throws Exception {
- mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
- mActivity = setUpActivityWithComponent();
- doReturn(true).when(mActivity.mAppCompatController
- .getAppCompatCameraOverrides()).isCameraActive();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
- .shouldOverrideMinAspectRatioForCamera());
- }
-
- @Test
- @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
- public void shouldOverrideMinAspectRatioForCamera_overrideDisabled_returnsFalse() {
- mActivity = setUpActivityWithComponent();
- doReturn(true).when(mActivity.mAppCompatController
- .getAppCompatCameraOverrides()).isCameraActive();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
- .shouldOverrideMinAspectRatioForCamera());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
- public void shouldOverrideMinAspectRatioForCamera_propertyFalse_overrideEnabled_returnsFalse()
- throws Exception {
- mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ false);
- mActivity = setUpActivityWithComponent();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
- .shouldOverrideMinAspectRatioForCamera());
- }
-
- @Test
- @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
- public void shouldOverrideMinAspectRatioForCamera_propertyFalse_noOverride_returnsFalse()
- throws Exception {
- mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ false);
-
- mActivity = setUpActivityWithComponent();
-
- doReturn(true).when(mActivity.mAppCompatController
- .getAppCompatCameraOverrides()).isCameraActive();
-
- assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
- .shouldOverrideMinAspectRatioForCamera());
- }
-
- @Test
@EnableCompatChanges({FORCE_RESIZE_APP})
public void testshouldOverrideForceResizeApp_overrideEnabled_returnsTrue() {
mController = new LetterboxUiController(mWm, mActivity);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
deleted file mode 100644
index d535677..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.internal.policy.TaskResizingAlgorithm.MIN_ASPECT;
-import static com.android.server.wm.WindowManagerService.dipToPixel;
-import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
-import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-import android.util.DisplayMetrics;
-import android.util.Log;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for the {@link TaskPositioner} class.
- *
- * Build/Install/Run:
- * atest WmTests:TaskPositionerTests
- */
-@SmallTest
-@Presubmit
-@RunWith(WindowTestRunner.class)
-public class TaskPositionerTests extends WindowTestsBase {
-
- private static final boolean DEBUGGING = false;
- private static final String TAG = "TaskPositionerTest";
-
- private static final int MOUSE_DELTA_X = 5;
- private static final int MOUSE_DELTA_Y = 5;
-
- private int mMinVisibleWidth;
- private int mMinVisibleHeight;
- private TaskPositioner mPositioner;
-
- @Before
- public void setUp() {
- TaskPositioner.setFactory(null);
-
- final DisplayMetrics dm = mDisplayContent.getDisplayMetrics();
-
- // This should be the same calculation as the TaskPositioner uses.
- mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm);
- mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm);
- removeGlobalMinSizeRestriction();
-
- final ActivityRecord activity = new ActivityBuilder(mAtm)
- .setCreateTask(true)
- .build();
- final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "window");
- mPositioner = new TaskPositioner(mWm);
- mPositioner.register(mDisplayContent, win);
-
- win.getRootTask().setWindowingMode(WINDOWING_MODE_FREEFORM);
- }
-
- @After
- public void tearDown() {
- TaskPositioner.setFactory(null);
- }
-
- @Test
- public void testOverrideFactory() {
- final boolean[] created = new boolean[1];
- created[0] = false;
- TaskPositioner.setFactory(new TaskPositioner.Factory() {
- @Override
- public TaskPositioner create(WindowManagerService service) {
- created[0] = true;
- return null;
- }
- });
-
- assertNull(TaskPositioner.create(mWm));
- assertTrue(created[0]);
- }
-
- /** This tests that the window can move in all directions. */
- @Test
- public void testMoveWindow() {
- final Rect displayBounds = mDisplayContent.getBounds();
- final int windowSize = Math.min(displayBounds.width(), displayBounds.height()) / 2;
- final int left = displayBounds.centerX() - windowSize / 2;
- final int top = displayBounds.centerY() - windowSize / 2;
- final Rect r = new Rect(left, top, left + windowSize, top + windowSize);
- mPositioner.mTask.setBounds(r);
- mPositioner.startDrag(false /* resizing */, false /* preserveOrientation */, left, top);
-
- // Move upper left.
- mPositioner.notifyMoveLocked(left - MOUSE_DELTA_X, top - MOUSE_DELTA_Y);
- r.offset(-MOUSE_DELTA_X, -MOUSE_DELTA_Y);
- assertBoundsEquals(r, mPositioner.getWindowDragBounds());
-
- // Move bottom right.
- mPositioner.notifyMoveLocked(left, top);
- r.offset(MOUSE_DELTA_X, MOUSE_DELTA_Y);
- assertBoundsEquals(r, mPositioner.getWindowDragBounds());
- }
-
- /**
- * This tests that free resizing will allow to change the orientation as well
- * as does some basic tests (e.g. dragging in Y only will keep X stable).
- */
- @Test
- public void testBasicFreeWindowResizing() {
- final Rect r = new Rect(100, 220, 700, 520);
- final int midY = (r.top + r.bottom) / 2;
- mPositioner.mTask.setBounds(r, true);
-
- // Start a drag resize starting upper left.
- mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
- r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
- assertBoundsEquals(r, mPositioner.getWindowDragBounds());
-
- // Drag to a good landscape size.
- mPositioner.resizeDrag(0.0f, 0.0f);
- assertBoundsEquals(new Rect(MOUSE_DELTA_X, MOUSE_DELTA_Y, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to a good portrait size.
- mPositioner.resizeDrag(400.0f, 0.0f);
- assertBoundsEquals(new Rect(400 + MOUSE_DELTA_X, MOUSE_DELTA_Y, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to a too small size for the width.
- mPositioner.resizeDrag(2000.0f, r.top);
- assertBoundsEquals(
- new Rect(r.right - mMinVisibleWidth, r.top + MOUSE_DELTA_Y, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to a too small size for the height.
- mPositioner.resizeDrag(r.left, 2000.0f);
- assertBoundsEquals(
- new Rect(r.left + MOUSE_DELTA_X, r.bottom - mMinVisibleHeight, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Start a drag resize left and see that only the left coord changes..
- mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
- r.left - MOUSE_DELTA_X, midY);
-
- // Drag to the left.
- mPositioner.resizeDrag(0.0f, midY);
- assertBoundsEquals(new Rect(MOUSE_DELTA_X, r.top, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to the right.
- mPositioner.resizeDrag(200.0f, midY);
- assertBoundsEquals(new Rect(200 + MOUSE_DELTA_X, r.top, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to the top
- mPositioner.resizeDrag(r.left, 0.0f);
- assertBoundsEquals(new Rect(r.left + MOUSE_DELTA_X, r.top, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to the bottom
- mPositioner.resizeDrag(r.left, 1000.0f);
- assertBoundsEquals(new Rect(r.left + MOUSE_DELTA_X, r.top, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
- }
-
- /**
- * This tests that by dragging any edge, the fixed / opposite edge(s) remains anchored.
- */
- @Test
- public void testFreeWindowResizingTestAllEdges() {
- final Rect r = new Rect(100, 220, 700, 520);
- final int midX = (r.left + r.right) / 2;
- final int midY = (r.top + r.bottom) / 2;
- mPositioner.mTask.setBounds(r, true);
-
- // Drag upper left.
- mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
- r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
- mPositioner.resizeDrag(0.0f, 0.0f);
- assertNotEquals(r.left, mPositioner.getWindowDragBounds().left);
- assertEquals(r.right, mPositioner.getWindowDragBounds().right);
- assertNotEquals(r.top, mPositioner.getWindowDragBounds().top);
- assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
-
- // Drag upper.
- mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */, midX,
- r.top - MOUSE_DELTA_Y);
- mPositioner.resizeDrag(0.0f, 0.0f);
- assertEquals(r.left, mPositioner.getWindowDragBounds().left);
- assertEquals(r.right, mPositioner.getWindowDragBounds().right);
- assertNotEquals(r.top, mPositioner.getWindowDragBounds().top);
- assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
-
- // Drag upper right.
- mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
- r.right + MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
- mPositioner.resizeDrag(r.right + 100, 0.0f);
- assertEquals(r.left, mPositioner.getWindowDragBounds().left);
- assertNotEquals(r.right, mPositioner.getWindowDragBounds().right);
- assertNotEquals(r.top, mPositioner.getWindowDragBounds().top);
- assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
-
- // Drag right.
- mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
- r.right + MOUSE_DELTA_X, midY);
- mPositioner.resizeDrag(r.right + 100, 0.0f);
- assertEquals(r.left, mPositioner.getWindowDragBounds().left);
- assertNotEquals(r.right, mPositioner.getWindowDragBounds().right);
- assertEquals(r.top, mPositioner.getWindowDragBounds().top);
- assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
-
- // Drag bottom right.
- mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
- r.right + MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
- mPositioner.resizeDrag(r.right + 100, r.bottom + 100);
- assertEquals(r.left, mPositioner.getWindowDragBounds().left);
- assertNotEquals(r.right, mPositioner.getWindowDragBounds().right);
- assertEquals(r.top, mPositioner.getWindowDragBounds().top);
- assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
-
- // Drag bottom.
- mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */, midX,
- r.bottom + MOUSE_DELTA_Y);
- mPositioner.resizeDrag(r.right + 100, r.bottom + 100);
- assertEquals(r.left, mPositioner.getWindowDragBounds().left);
- assertEquals(r.right, mPositioner.getWindowDragBounds().right);
- assertEquals(r.top, mPositioner.getWindowDragBounds().top);
- assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
-
- // Drag bottom left.
- mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
- r.left - MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
- mPositioner.resizeDrag(0.0f, r.bottom + 100);
- assertNotEquals(r.left, mPositioner.getWindowDragBounds().left);
- assertEquals(r.right, mPositioner.getWindowDragBounds().right);
- assertEquals(r.top, mPositioner.getWindowDragBounds().top);
- assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
-
- // Drag left.
- mPositioner.startDrag(true /* resizing */, false /* preserveOrientation */,
- r.left - MOUSE_DELTA_X, midY);
- mPositioner.resizeDrag(0.0f, r.bottom + 100);
- assertNotEquals(r.left, mPositioner.getWindowDragBounds().left);
- assertEquals(r.right, mPositioner.getWindowDragBounds().right);
- assertEquals(r.top, mPositioner.getWindowDragBounds().top);
- assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
- }
-
- /**
- * This tests that a constrained landscape window will keep the aspect and do the
- * right things upon resizing when dragged from the top left corner.
- */
- @Test
- public void testLandscapePreservedWindowResizingDragTopLeft() {
- final Rect r = new Rect(100, 220, 700, 520);
- mPositioner.mTask.setBounds(r, true);
-
- mPositioner.startDrag(true /* resizing */, true /* preserveOrientation */,
- r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
- assertBoundsEquals(r, mPositioner.getWindowDragBounds());
-
- // Drag to a good landscape size.
- mPositioner.resizeDrag(0.0f, 0.0f);
- assertBoundsEquals(new Rect(MOUSE_DELTA_X, MOUSE_DELTA_Y, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to a good portrait size.
- mPositioner.resizeDrag(400.0f, 0.0f);
- int width = Math.round((float) (r.bottom - MOUSE_DELTA_Y) * MIN_ASPECT);
- assertBoundsEquals(new Rect(r.right - width, MOUSE_DELTA_Y, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to a too small size for the width.
- mPositioner.resizeDrag(2000.0f, r.top);
- final int w = mMinVisibleWidth;
- final int h = Math.round(w / MIN_ASPECT);
- assertBoundsEquals(new Rect(r.right - w, r.bottom - h, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to a too small size for the height.
- mPositioner.resizeDrag(r.left, 2000.0f);
- assertBoundsEquals(
- new Rect(r.left + MOUSE_DELTA_X, r.bottom - mMinVisibleHeight, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
- }
-
- /**
- * This tests that a constrained landscape window will keep the aspect and do the
- * right things upon resizing when dragged from the left corner.
- */
- @Test
- public void testLandscapePreservedWindowResizingDragLeft() {
- final Rect r = new Rect(100, 220, 700, 520);
- final int midY = (r.top + r.bottom) / 2;
- mPositioner.mTask.setBounds(r, true);
-
- mPositioner.startDrag(true /* resizing */, true /* preserveOrientation */,
- r.left - MOUSE_DELTA_X, midY);
-
- // Drag to the left.
- mPositioner.resizeDrag(0.0f, midY);
- assertBoundsEquals(new Rect(MOUSE_DELTA_X, r.top, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to the right.
- mPositioner.resizeDrag(200.0f, midY);
- assertBoundsEquals(new Rect(200 + MOUSE_DELTA_X, r.top, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag all the way to the right and see the height also shrinking.
- mPositioner.resizeDrag(2000.0f, midY);
- final int w = mMinVisibleWidth;
- final int h = Math.round((float) w / MIN_ASPECT);
- assertBoundsEquals(new Rect(r.right - w, r.top, r.right, r.top + h),
- mPositioner.getWindowDragBounds());
-
- // Drag to the top.
- mPositioner.resizeDrag(r.left, 0.0f);
- assertBoundsEquals(new Rect(r.left + MOUSE_DELTA_X, r.top, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to the bottom.
- mPositioner.resizeDrag(r.left, 1000.0f);
- assertBoundsEquals(new Rect(r.left + MOUSE_DELTA_X, r.top, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
- }
-
- /**
- * This tests that a constrained landscape window will keep the aspect and do the
- * right things upon resizing when dragged from the top corner.
- */
- @Test
- public void testLandscapePreservedWindowResizingDragTop() {
- final Rect r = new Rect(100, 220, 700, 520);
- final int midX = (r.left + r.right) / 2;
- mPositioner.mTask.setBounds(r, true);
-
- mPositioner.startDrag(true /*resizing*/, true /*preserveOrientation*/, midX,
- r.top - MOUSE_DELTA_Y);
-
- // Drag to the left (no change).
- mPositioner.resizeDrag(0.0f, r.top);
- assertBoundsEquals(new Rect(r.left, r.top + MOUSE_DELTA_Y, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to the right (no change).
- mPositioner.resizeDrag(2000.0f, r.top);
- assertBoundsEquals(new Rect(r.left , r.top + MOUSE_DELTA_Y, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to the top.
- mPositioner.resizeDrag(300.0f, 0.0f);
- int h = r.bottom - MOUSE_DELTA_Y;
- int w = Math.max(r.right - r.left, Math.round(h * MIN_ASPECT));
- assertBoundsEquals(new Rect(r.left, MOUSE_DELTA_Y, r.left + w, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to the bottom.
- mPositioner.resizeDrag(r.left, 1000.0f);
- h = mMinVisibleHeight;
- assertBoundsEquals(new Rect(r.left, r.bottom - h, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
- }
-
- /**
- * This tests that a constrained portrait window will keep the aspect and do the
- * right things upon resizing when dragged from the top left corner.
- */
- @Test
- public void testPortraitPreservedWindowResizingDragTopLeft() {
- final Rect r = new Rect(330, 100, 630, 600);
- mPositioner.mTask.setBounds(r, true);
-
- mPositioner.startDrag(true /*resizing*/, true /*preserveOrientation*/,
- r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
- assertBoundsEquals(r, mPositioner.getWindowDragBounds());
-
- // Drag to a good landscape size.
- mPositioner.resizeDrag(0.0f, 0.0f);
- int height = Math.round((float) (r.right - MOUSE_DELTA_X) * MIN_ASPECT);
- assertBoundsEquals(new Rect(MOUSE_DELTA_X, r.bottom - height, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to a good portrait size.
- mPositioner.resizeDrag(400.0f, 0.0f);
- assertBoundsEquals(new Rect(400 + MOUSE_DELTA_X, MOUSE_DELTA_Y, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to a too small size for the height and the the width shrinking.
- mPositioner.resizeDrag(r.left + MOUSE_DELTA_X, 2000.0f);
- final int w = Math.max(mMinVisibleWidth, Math.round(mMinVisibleHeight / MIN_ASPECT));
- final int h = Math.max(mMinVisibleHeight, Math.round(w * MIN_ASPECT));
- assertBoundsEquals(
- new Rect(r.right - w, r.bottom - h, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
- }
-
- /**
- * This tests that a constrained portrait window will keep the aspect and do the
- * right things upon resizing when dragged from the left corner.
- */
- @Test
- public void testPortraitPreservedWindowResizingDragLeft() {
- final Rect r = new Rect(330, 100, 630, 600);
- final int midY = (r.top + r.bottom) / 2;
- mPositioner.mTask.setBounds(r, true);
-
- mPositioner.startDrag(true /* resizing */, true /* preserveOrientation */,
- r.left - MOUSE_DELTA_X, midY);
-
- // Drag to the left.
- mPositioner.resizeDrag(0.0f, midY);
- int w = r.right - MOUSE_DELTA_X;
- int h = Math.round(w * MIN_ASPECT);
- assertBoundsEquals(new Rect(MOUSE_DELTA_X, r.top, r.right, r.top + h),
- mPositioner.getWindowDragBounds());
-
- // Drag to the right.
- mPositioner.resizeDrag(450.0f, midY);
- assertBoundsEquals(new Rect(450 + MOUSE_DELTA_X, r.top, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag all the way to the right.
- mPositioner.resizeDrag(2000.0f, midY);
- w = mMinVisibleWidth;
- h = Math.max(Math.round((float) w * MIN_ASPECT), r.height());
- assertBoundsEquals(new Rect(r.right - w, r.top, r.right, r.top + h),
- mPositioner.getWindowDragBounds());
-
- // Drag to the top.
- mPositioner.resizeDrag(r.left, 0.0f);
- assertBoundsEquals(new Rect(r.left + MOUSE_DELTA_X, r.top, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to the bottom.
- mPositioner.resizeDrag(r.left, 1000.0f);
- assertBoundsEquals(new Rect(r.left + MOUSE_DELTA_X, r.top, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
- }
-
- /**
- * This tests that a constrained portrait window will keep the aspect and do the
- * right things upon resizing when dragged from the top corner.
- */
- @Test
- public void testPortraitPreservedWindowResizingDragTop() {
- final Rect r = new Rect(330, 100, 630, 600);
- final int midX = (r.left + r.right) / 2;
- mPositioner.mTask.setBounds(r, true);
-
- mPositioner.startDrag(true /* resizing */, true /* preserveOrientation */, midX,
- r.top - MOUSE_DELTA_Y);
-
- // Drag to the left (no change).
- mPositioner.resizeDrag(0.0f, r.top);
- assertBoundsEquals(new Rect(r.left, r.top + MOUSE_DELTA_Y, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to the right (no change).
- mPositioner.resizeDrag(2000.0f, r.top);
- assertBoundsEquals(new Rect(r.left , r.top + MOUSE_DELTA_Y, r.right, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to the top.
- mPositioner.resizeDrag(300.0f, 0.0f);
- int h = r.bottom - MOUSE_DELTA_Y;
- int w = Math.min(r.width(), Math.round(h / MIN_ASPECT));
- assertBoundsEquals(new Rect(r.left, MOUSE_DELTA_Y, r.left + w, r.bottom),
- mPositioner.getWindowDragBounds());
-
- // Drag to the bottom.
- mPositioner.resizeDrag(r.left, 1000.0f);
- h = Math.max(mMinVisibleHeight, Math.round(mMinVisibleWidth * MIN_ASPECT));
- w = Math.round(h / MIN_ASPECT);
- assertBoundsEquals(new Rect(r.left, r.bottom - h, r.left + w, r.bottom),
- mPositioner.getWindowDragBounds());
- }
-
- private static void assertBoundsEquals(Rect expected, Rect actual) {
- if (DEBUGGING) {
- if (!expected.equals(actual)) {
- Log.e(TAG, "rect(" + actual.toString() + ") != isRect(" + actual.toString()
- + ") " + Log.getStackTraceString(new Throwable()));
- }
- }
- assertEquals(expected, actual);
- }
-
- @Test
- public void testFinishingMovingWhenBinderDied() {
- spyOn(mWm.mTaskPositioningController);
-
- mPositioner.startDrag(false, false, 0 /* startX */, 0 /* startY */);
- verify(mWm.mTaskPositioningController, never()).finishTaskPositioning();
- mPositioner.binderDied();
- verify(mWm.mTaskPositioningController).finishTaskPositioning();
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
deleted file mode 100644
index bfc13d3..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.platform.test.annotations.Presubmit;
-import android.view.InputChannel;
-
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for the {@link TaskPositioningController} class.
- *
- * Build/Install/Run:
- * atest WmTests:TaskPositioningControllerTests
- */
-@SmallTest
-@Presubmit
-@RunWith(WindowTestRunner.class)
-public class TaskPositioningControllerTests extends WindowTestsBase {
- private static final int TIMEOUT_MS = 1000;
-
- private TaskPositioningController mTarget;
- private WindowState mWindow;
-
- @Before
- public void setUp() throws Exception {
- assertNotNull(mWm.mTaskPositioningController);
- mTarget = mWm.mTaskPositioningController;
-
- when(mWm.mInputManager.transferTouchGesture(any(), any())).thenReturn(true);
-
- mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
- mWindow.getTask().setResizeMode(RESIZE_MODE_RESIZEABLE);
- mWindow.mInputChannel = new InputChannel();
- mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
- doReturn(mock(InputMonitor.class)).when(mDisplayContent).getInputMonitor();
- }
-
- @FlakyTest(bugId = 291067614)
- @Test
- public void testStartAndFinishPositioning() {
- assertFalse(mTarget.isPositioningLocked());
- assertNull(mTarget.getDragWindowHandleLocked());
-
- assertTrue(mTarget.startMovingTask(mWindow.mClient, 0, 0));
-
- assertTrue(mTarget.isPositioningLocked());
- assertNotNull(mTarget.getDragWindowHandleLocked());
-
- mTarget.finishTaskPositioning();
- // Wait until the looper processes finishTaskPositioning.
- assertTrue(waitHandlerIdle(mWm.mAnimationHandler, TIMEOUT_MS));
-
- assertFalse(mTarget.isPositioningLocked());
- assertNull(mTarget.getDragWindowHandleLocked());
- }
-
- @Test
- public void testFinishPositioningWhenAppRequested() {
- assertFalse(mTarget.isPositioningLocked());
- assertNull(mTarget.getDragWindowHandleLocked());
-
- assertTrue(mTarget.startMovingTask(mWindow.mClient, 0, 0));
-
- assertTrue(mTarget.isPositioningLocked());
- assertNotNull(mTarget.getDragWindowHandleLocked());
-
- mTarget.finishTaskPositioning(mWindow.mClient);
- // Wait until the looper processes finishTaskPositioning.
- assertTrue(waitHandlerIdle(mWm.mAnimationHandler, TIMEOUT_MS));
-
- assertFalse(mTarget.isPositioningLocked());
- assertNull(mTarget.getDragWindowHandleLocked());
- }
-
- @Test
- public void testHandleTapOutsideTask() {
- assertFalse(mTarget.isPositioningLocked());
- assertNull(mTarget.getDragWindowHandleLocked());
-
- final DisplayContent content = mock(DisplayContent.class);
- doReturn(mWindow.getTask()).when(content).findTaskForResizePoint(anyInt(), anyInt());
- assertNotNull(mWindow.getTask().getTopVisibleAppMainWindow());
-
- mTarget.handleTapOutsideTask(content, 0, 0);
- // Wait until the looper processes handleTapOutsideTask.
- assertTrue(waitHandlerIdle(mWm.mH, TIMEOUT_MS));
-
- assertTrue(mTarget.isPositioningLocked());
- assertNotNull(mTarget.getDragWindowHandleLocked());
-
- mTarget.finishTaskPositioning();
- // Wait until the looper processes finishTaskPositioning.
- assertTrue(waitHandlerIdle(mWm.mAnimationHandler, TIMEOUT_MS));
-
- assertFalse(mTarget.isPositioningLocked());
- assertNull(mTarget.getDragWindowHandleLocked());
- }
-
- @Test
- public void testHandleTapOutsideNonResizableTask() {
- assertFalse(mTarget.isPositioningLocked());
- assertNull(mTarget.getDragWindowHandleLocked());
-
- final DisplayContent content = mock(DisplayContent.class);
- doReturn(mWindow.getTask()).when(content).findTaskForResizePoint(anyInt(), anyInt());
- assertNotNull(mWindow.getTask().getTopVisibleAppMainWindow());
-
- mWindow.getTask().setResizeMode(RESIZE_MODE_UNRESIZEABLE);
-
- mTarget.handleTapOutsideTask(content, 0, 0);
- // Wait until the looper processes handleTapOutsideTask.
- assertTrue(waitHandlerIdle(mWm.mH, TIMEOUT_MS));
-
- assertFalse(mTarget.isPositioningLocked());
- }
-
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 7d01b79..720457e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1573,7 +1573,8 @@
enteringAnimReports.clear();
doCallRealMethod().when(mWm.mRoot).ensureActivitiesVisible(any(), anyBoolean());
final boolean[] wasInFinishingTransition = { false };
- controller.registerLegacyListener(new WindowManagerInternal.AppTransitionListener() {
+ controller.registerLegacyListener(new WindowManagerInternal.AppTransitionListener(
+ mDisplayContent.mDisplayId) {
@Override
public void onAppTransitionFinishedLocked(IBinder token) {
final ActivityRecord r = ActivityRecord.forToken(token);
@@ -1582,6 +1583,14 @@
}
}
});
+ final boolean[] calledListenerOnOtherDisplay = { false };
+ controller.registerLegacyListener(new WindowManagerInternal.AppTransitionListener(
+ mDisplayContent.mDisplayId + 1234) {
+ @Override
+ public void onAppTransitionFinishedLocked(IBinder token) {
+ calledListenerOnOtherDisplay[0] = true;
+ }
+ });
assertTrue(activity1.isVisible());
doReturn(false).when(task1).isTranslucent(null);
doReturn(false).when(task1).isTranslucentForTransition();
@@ -1592,6 +1601,7 @@
controller.finishTransition(closeTransition);
assertTrue(wasInFinishingTransition[0]);
+ assertFalse(calledListenerOnOtherDisplay[0]);
assertNull(controller.mFinishingTransition);
assertTrue(activity2.isVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index e6648da..0cb22ad 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -18,6 +18,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.content.pm.ActivityInfo.INSETS_DECOUPLED_CONFIGURATION_ENFORCED;
import static android.content.res.Configuration.GRAMMATICAL_GENDER_NOT_SPECIFIED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -86,6 +87,7 @@
ApplicationInfo info = mock(ApplicationInfo.class);
info.packageName = "test.package.name";
+ doReturn(true).when(info).isChangeEnabled(INSETS_DECOUPLED_CONFIGURATION_ENFORCED);
mWpc = new WindowProcessController(
mAtm, info, null, 0, -1, null, mMockListener);
mWpc.setThread(mock(IApplicationThread.class));
diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
index b6672a0..fad94d4 100644
--- a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
+++ b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
@@ -698,7 +698,7 @@
traceMonitor.start();
mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP,
- "My test null string: %s", null);
+ "My test null string: %s", (Object) null);
} finally {
traceMonitor.stop(mWriter);
}