Merge "Shortcut Helper - Define mapping of key codes to strings / icons" into main
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 4536f6f..cd2c9ca 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -3524,6 +3524,7 @@
field @Deprecated public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1
field @FlaggedApi("android.companion.virtual.flags.dynamic_policy") public static final int POLICY_TYPE_ACTIVITY = 3; // 0x3
field public static final int POLICY_TYPE_AUDIO = 1; // 0x1
+ field @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public static final int POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR = 6; // 0x6
field @FlaggedApi("android.companion.virtual.flags.virtual_camera") public static final int POLICY_TYPE_CAMERA = 5; // 0x5
field @FlaggedApi("android.companion.virtual.flags.cross_device_clipboard") public static final int POLICY_TYPE_CLIPBOARD = 4; // 0x4
field public static final int POLICY_TYPE_RECENTS = 2; // 0x2
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index bd80dc1..69b5222 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -499,32 +499,31 @@
/**
* Activity Action: Launch an Automatic Zen Rule configuration screen
- * <p>
- * Input: Optionally, {@link #EXTRA_AUTOMATIC_RULE_ID}, if the configuration screen for an
+ *
+ * <p> Input: Optionally, {@link #EXTRA_AUTOMATIC_RULE_ID}, if the configuration screen for an
* existing rule should be displayed. If the rule id is missing or null, apps should display
* a configuration screen where users can create a new instance of the rule.
- * <p>
- * Output: Nothing
- * <p>
- * You can have multiple activities handling this intent, if you support multiple
- * {@link AutomaticZenRule rules}. In order for the system to properly display all of your
- * rule types so that users can create new instances or configure existing ones, you need
- * to add some extra metadata ({@link #META_DATA_AUTOMATIC_RULE_TYPE})
- * to your activity tag in your manifest. If you'd like to limit the number of rules a user
- * can create from this flow, you can additionally optionally include
- * {@link #META_DATA_RULE_INSTANCE_LIMIT}.
*
- * For example,
- * <meta-data
- * android:name="android.app.zen.automatic.ruleType"
- * android:value="@string/my_condition_rule">
- * </meta-data>
- * <meta-data
- * android:name="android.app.zen.automatic.ruleInstanceLimit"
- * android:value="1">
- * </meta-data>
- * </p>
- * </p>
+ * <p> Output: Nothing
+ *
+ * <p> You can have multiple activities handling this intent, if you support multiple
+ * {@link AutomaticZenRule rules}. In order for the system to properly display all of your
+ * rule types so that users can create new instances or configure existing ones, you need
+ * to add some extra metadata ({@link #META_DATA_AUTOMATIC_RULE_TYPE})
+ * to your activity tag in your manifest. If you'd like to limit the number of rules a user
+ * can create from this flow, you can additionally optionally include
+ * {@link #META_DATA_RULE_INSTANCE_LIMIT}. For example,
+ *
+ * <pre>
+ * {@code
+ * <meta-data
+ * android:name="android.service.zen.automatic.ruleType"
+ * android:value="@string/my_condition_rule" />
+ * <meta-data
+ * android:name="android.service.zen.automatic.ruleInstanceLimit"
+ * android:value="1" />
+ * }
+ * </pre>
*
* @see #addAutomaticZenRule(AutomaticZenRule)
*/
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index f9a9da1..f7f842f 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -171,7 +171,7 @@
* @hide
*/
@IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY,
- POLICY_TYPE_CLIPBOARD})
+ POLICY_TYPE_CLIPBOARD, POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR})
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
public @interface DynamicPolicyType {}
@@ -263,6 +263,22 @@
@FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA)
public static final int POLICY_TYPE_CAMERA = 5;
+ /**
+ * Tells the virtual device framework how to handle activity launches that were blocked due to
+ * the current activity policy.
+ *
+ * <ul>
+ * <li>{@link #DEVICE_POLICY_DEFAULT}: Show UI informing the user of the blocked activity
+ * launch on the virtual display that the activity was originally launched on.
+ * <li>{@link #DEVICE_POLICY_CUSTOM}: Does not inform the user of the blocked activity
+ * launch. The virtual device owner can use this policy together with
+ * {@link VirtualDeviceManager.ActivityListener#onActivityLaunchBlocked} to provide custom
+ * experience on the virtual device.
+ * </ul>
+ */
+ @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API)
+ public static final int POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR = 6;
+
private final int mLockState;
@NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
@NavigationPolicy
@@ -1174,6 +1190,10 @@
mDevicePolicies.delete(POLICY_TYPE_CAMERA);
}
+ if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) {
+ mDevicePolicies.delete(POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR);
+ }
+
if ((mAudioPlaybackSessionId != AUDIO_SESSION_ID_GENERATE
|| mAudioRecordingSessionId != AUDIO_SESSION_ID_GENERATE)
&& mDevicePolicies.get(POLICY_TYPE_AUDIO, DEVICE_POLICY_DEFAULT)
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 065b3d6..b2f333a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -9025,6 +9025,10 @@
final int uid = consumer.getUid();
final Uid u = uidStats.get(uid);
+ if (u == null) {
+ continue;
+ }
+
final long rxPackets = u.getNetworkActivityPackets(
BatteryStats.NETWORK_MOBILE_RX_DATA, STATS_SINCE_CHARGED);
final long txPackets = u.getNetworkActivityPackets(
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index a459aaa..2c7b9c0 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -159,6 +159,8 @@
@UnsupportedAppUsage
private static UserEnvironment sCurrentUser;
private static boolean sUserRequired;
+ private static Boolean sLegacyStorageAppOp;
+ private static Boolean sNoIsolatedStorageAppOp;
static {
initForCurrentUser();
@@ -1459,15 +1461,23 @@
final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
final String opPackageName = context.getOpPackageName();
- if (appOps.noteOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, uid,
- opPackageName) == AppOpsManager.MODE_ALLOWED) {
- return true;
+ if (sLegacyStorageAppOp == null) {
+ sLegacyStorageAppOp =
+ appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE, uid, opPackageName) ==
+ AppOpsManager.MODE_ALLOWED;
+ }
+ if (sLegacyStorageAppOp) {
+ return sLegacyStorageAppOp;
}
// Legacy external storage access is granted to instrumentations invoked with
// "--no-isolated-storage" flag.
- return appOps.noteOpNoThrow(AppOpsManager.OP_NO_ISOLATED_STORAGE, uid,
- opPackageName) == AppOpsManager.MODE_ALLOWED;
+ if (sNoIsolatedStorageAppOp == null) {
+ sNoIsolatedStorageAppOp =
+ appOps.checkOpNoThrow(AppOpsManager.OP_NO_ISOLATED_STORAGE, uid,
+ opPackageName) == AppOpsManager.MODE_ALLOWED;
+ }
+ return sNoIsolatedStorageAppOp;
}
private static boolean isScopedStorageEnforced(boolean defaultScopedStorage,
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7926afe..f30a9f5 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -6367,6 +6367,33 @@
Settings.Global.DEVICE_DEMO_MODE, 0) > 0;
}
+ private static final String CACHE_KEY_USER_SERIAL_NUMBER_PROPERTY =
+ PropertyInvalidatedCache.createPropertyName(
+ PropertyInvalidatedCache.MODULE_SYSTEM, "user_serial_number");
+
+ private final PropertyInvalidatedCache<Integer, Integer> mUserSerialNumberCache =
+ new PropertyInvalidatedCache<Integer, Integer>(
+ 32, CACHE_KEY_USER_SERIAL_NUMBER_PROPERTY) {
+ @Override
+ public Integer recompute(Integer query) {
+ try {
+ return mService.getUserSerialNumber(query);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+ @Override
+ public boolean bypass(Integer query) {
+ return query <= 0;
+ }
+ };
+
+
+ /** @hide */
+ public static final void invalidateUserSerialNumberCache() {
+ PropertyInvalidatedCache.invalidateCache(CACHE_KEY_USER_SERIAL_NUMBER_PROPERTY);
+ }
+
/**
* Returns a serial number on this device for a given userId. User handles can be recycled
* when deleting and creating users, but serial numbers are not reused until the device is wiped.
@@ -6376,6 +6403,14 @@
*/
@UnsupportedAppUsage
public int getUserSerialNumber(@UserIdInt int userId) {
+ if (android.multiuser.Flags.cacheUserSerialNumber()) {
+ // System user serial number is always 0, and it always exists.
+ // There is no need to call binder for that.
+ if (userId == UserHandle.USER_SYSTEM) {
+ return UserHandle.USER_SERIAL_SYSTEM;
+ }
+ return mUserSerialNumberCache.query(userId);
+ }
try {
return mService.getUserSerialNumber(userId);
} catch (RemoteException re) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 57853e7..94c76929 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13396,7 +13396,19 @@
= "enable_freeform_support";
/**
- * Whether to enable experimental desktop mode on secondary displays.
+ * Whether to override the availability of the desktop mode on the main display of the
+ * device. If on, users can make move an app to the desktop, allowing a freeform windowing
+ * experience.
+ * @hide
+ */
+ @Readable
+ public static final String DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES =
+ "override_desktop_mode_features";
+
+ /**
+ * Whether to enable the legacy freeform support on secondary displays. If enabled, the
+ * SECONDARY_HOME of the launcher is started on any secondary display, allowing for a
+ * desktop experience.
* @hide
*/
@Readable
diff --git a/core/java/android/tracing/flags.aconfig b/core/java/android/tracing/flags.aconfig
index d7389ba..be60c25 100644
--- a/core/java/android/tracing/flags.aconfig
+++ b/core/java/android/tracing/flags.aconfig
@@ -38,3 +38,11 @@
is_fixed_read_only: true
bug: "323166383"
}
+
+flag {
+ name: "perfetto_wm_tracing"
+ namespace: "windowing_tools"
+ description: "Migrate WindowManager tracing to Perfetto"
+ is_fixed_read_only: true
+ bug: "323165543"
+}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 02ea6d4..df2af73 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -29,6 +29,7 @@
import static android.view.WindowInsets.Type.ime;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+import static com.android.window.flags.Flags.insetsControlSeq;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -890,7 +891,9 @@
@InsetsType int visibleTypes = 0;
@InsetsType int[] cancelledUserAnimationTypes = {0};
for (int i = 0, size = newState.sourceSize(); i < size; i++) {
- final InsetsSource source = newState.sourceAt(i);
+ final InsetsSource source = insetsControlSeq()
+ ? new InsetsSource(newState.sourceAt(i))
+ : newState.sourceAt(i);
@InsetsType int type = source.getType();
@AnimationType int animationType = getAnimationType(type);
final InsetsSourceConsumer consumer = mSourceConsumers.get(source.getId());
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 6a92fd9..c73cbc6 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -28,6 +28,7 @@
import static android.view.InsetsSourceConsumerProto.TYPE_NUMBER;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+import static com.android.window.flags.Flags.insetsControlSeq;
import android.annotation.IntDef;
import android.annotation.Nullable;
@@ -410,7 +411,9 @@
// Frame is changing while animating. Keep note of the new frame but keep existing frame
// until animation is finished.
- newSource = new InsetsSource(newSource);
+ if (!insetsControlSeq()) {
+ newSource = new InsetsSource(newSource);
+ }
mPendingFrame = new Rect(newSource.getFrame());
mPendingVisibleFrame = newSource.getVisibleFrame() != null
? new Rect(newSource.getVisibleFrame())
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cda58e38..1525bd1 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -114,6 +114,7 @@
import static android.view.accessibility.Flags.forceInvertColor;
import static android.view.accessibility.Flags.reduceWindowContentChangedEventThrottle;
import static android.view.flags.Flags.addSchandleToVriSurface;
+import static android.view.flags.Flags.disableDrawWakeLock;
import static android.view.flags.Flags.sensitiveContentAppProtection;
import static android.view.flags.Flags.sensitiveContentPrematureProtectionRemovedFix;
import static android.view.flags.Flags.toolkitFrameRateFunctionEnablingReadOnly;
@@ -149,6 +150,8 @@
import android.app.WindowConfiguration;
import android.app.compat.CompatChanges;
import android.app.servertransaction.WindowStateTransactionItem;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -337,6 +340,15 @@
private static final int LOGTAG_VIEWROOT_DRAW_EVENT = 60004;
/**
+ * This change disables the {@code DRAW_WAKE_LOCK}, an internal wakelock acquired per-frame
+ * duration display DOZE. It was added to allow animation during AOD. This wakelock consumes
+ * battery severely if the animation is too heavy, so, it will be removed.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ private static final long DISABLE_DRAW_WAKE_LOCK = 349153669L;
+
+ /**
* Set to false if we do not want to use the multi threaded renderer even though
* threaded renderer (aka hardware renderering) is used. Note that by disabling
* this, WindowCallbacks will not fire.
@@ -2459,6 +2471,11 @@
}
void pokeDrawLockIfNeeded() {
+ // Disable DRAW_WAKE_LOCK starting U. Otherwise, only need to acquire it for DOZE state.
+ if (CompatChanges.isChangeEnabled(DISABLE_DRAW_WAKE_LOCK) && disableDrawWakeLock()) {
+ return;
+ }
+
if (!Display.isDozeState(mAttachInfo.mDisplayState)) {
// Only need to acquire wake lock for DOZE state.
return;
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index 199a69a..5b1c7d5 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -256,6 +256,21 @@
"ignore_relayout_auth_pending";
/**
+ * Fixes to handle apps relaying out, and causing problems for autofill.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_ENABLE_RELAYOUT = "enable_relayout";
+
+ /**
+ * Enable relative location of views for fingerprinting for relayout.
+ *
+ * @hide
+ */
+ public static final String DEVICE_CONFIG_ENABLE_RELATIVE_LOCATION_FOR_RELAYOUT =
+ "enable_relative_location_for_relayout";
+
+ /**
* Bugfix flag, Autofill should only fill in value from current session.
*
* See frameworks/base/services/autofill/bugfixes.aconfig#fill_fields_from_current_session_only
@@ -543,6 +558,22 @@
false);
}
+ /** @hide */
+ public static boolean enableRelayoutFixes() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_ENABLE_RELAYOUT,
+ true);
+ }
+
+ /** @hide */
+ public static boolean enableRelativeLocationForRelayout() {
+ return DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_AUTOFILL,
+ DEVICE_CONFIG_ENABLE_RELATIVE_LOCATION_FOR_RELAYOUT,
+ false);
+ }
+
/** @hide **/
public static boolean shouldFillFieldsFromCurrentSessionOnly() {
return DeviceConfig.getBoolean(
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 0d4c556..515ed0e 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -748,7 +748,16 @@
// Controls logic around apps changing some properties of their views when activity loses
// focus due to autofill showing biometric activity, password manager, or password breach check.
- private boolean mRelayoutFix;
+ // Deprecated. TODO: Remove it after ramp of new solution.
+ private boolean mRelayoutFixDeprecated;
+
+ // Controls logic around apps changing some properties of their views when activity loses
+ // focus due to autofill showing biometric activity, password manager, or password breach check.
+ private final boolean mRelayoutFix;
+
+ // Controls logic around apps changing some properties of their views when activity loses
+ // focus due to autofill showing biometric activity, password manager, or password breach check.
+ private final boolean mRelativePositionForRelayout;
// Indicates whether the credman integration is enabled.
private final boolean mIsCredmanIntegrationEnabled;
@@ -978,11 +987,31 @@
mShouldIncludeInvisibleViewInAssistStructure =
AutofillFeatureFlags.shouldIncludeInvisibleViewInAssistStructure();
- mRelayoutFix = AutofillFeatureFlags.shouldIgnoreRelayoutWhenAuthPending();
+ mRelayoutFixDeprecated = AutofillFeatureFlags.shouldIgnoreRelayoutWhenAuthPending();
+ mRelayoutFix = AutofillFeatureFlags.enableRelayoutFixes();
+ mRelativePositionForRelayout = AutofillFeatureFlags.enableRelativeLocationForRelayout();
mIsCredmanIntegrationEnabled = Flags.autofillCredmanIntegration();
}
/**
+ * Whether to apply relayout fixes.
+ *
+ * @hide
+ */
+ public boolean isRelayoutFixEnabled() {
+ return mRelayoutFix;
+ }
+
+ /**
+ * Whether to use relative positions and locations of the views for disambiguation.
+ *
+ * @hide
+ */
+ public boolean isRelativePositionForRelayoutEnabled() {
+ return mRelativePositionForRelayout;
+ }
+
+ /**
* Whether to apply heuristic check on important views before triggering fill request
*
* @hide
@@ -1779,7 +1808,7 @@
}
return;
}
- if (mRelayoutFix && mState == STATE_PENDING_AUTHENTICATION) {
+ if (mRelayoutFixDeprecated && mState == STATE_PENDING_AUTHENTICATION) {
if (sVerbose) {
Log.v(TAG, "notifyViewVisibilityChanged(): ignoring in auth pending mode");
}
@@ -2917,7 +2946,7 @@
Intent fillInIntent, boolean authenticateInline) {
synchronized (mLock) {
if (sessionId == mSessionId) {
- if (mRelayoutFix) {
+ if (mRelayoutFixDeprecated) {
mState = STATE_PENDING_AUTHENTICATION;
}
final AutofillClient client = getClient();
@@ -3778,7 +3807,7 @@
@GuardedBy("mLock")
private boolean isPendingAuthenticationLocked() {
- return mRelayoutFix && mState == STATE_PENDING_AUTHENTICATION;
+ return mRelayoutFixDeprecated && mState == STATE_PENDING_AUTHENTICATION;
}
@GuardedBy("mLock")
@@ -4322,6 +4351,13 @@
addToSet(mInvisibleDialogTrackedIds, id);
}
}
+ } else {
+ if (sDebug) {
+ // isClientVisibleForAutofillLocked() is checking whether
+ // activity has stopped under the hood
+ Log.d(TAG, "notifyViewVisibilityChangedLocked(): ignoring "
+ + "view visibility change since activity has stopped");
+ }
}
if (mIsTrackedSaveView && mVisibleTrackedIds.isEmpty()) {
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index 4d4e4af..f570a9a 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -89,4 +89,12 @@
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "disable_draw_wake_lock"
+ namespace: "wear_frameworks"
+ description: "Disable Draw Wakelock starting U."
+ bug: "331698645"
+ is_fixed_read_only: true
}
\ No newline at end of file
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 8cd2a3e..68e33c6 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -181,3 +181,14 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ namespace: "windowing_sdk"
+ name: "per_user_display_window_settings"
+ description: "Whether to store display window settings per user to avoid conflicts"
+ bug: "346668297"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
index 6420620..a3fcfad 100644
--- a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
+++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
@@ -72,6 +72,7 @@
UserShortcutType.TRIPLETAP,
UserShortcutType.TWOFINGER_DOUBLETAP,
UserShortcutType.QUICK_SETTINGS,
+ UserShortcutType.GESTURE
})
public @interface UserShortcutType {
int DEFAULT = 0;
@@ -81,6 +82,7 @@
int TRIPLETAP = 1 << 2;
int TWOFINGER_DOUBLETAP = 1 << 3;
int QUICK_SETTINGS = 1 << 4;
+ int GESTURE = 1 << 5;
// LINT.ThenChange(:shortcut_type_array)
}
@@ -95,6 +97,7 @@
UserShortcutType.TRIPLETAP,
UserShortcutType.TWOFINGER_DOUBLETAP,
UserShortcutType.QUICK_SETTINGS,
+ UserShortcutType.GESTURE
// LINT.ThenChange(:shortcut_type_intdef)
};
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
index c8d6194..01cbb55 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
@@ -20,6 +20,7 @@
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
import static com.android.internal.accessibility.util.AccessibilityStatsLogUtils.logAccessibilityButtonLongPressStatus;
@@ -66,6 +67,9 @@
NAV_BAR_MODE_GESTURAL == getResources().getInteger(
com.android.internal.R.integer.config_navBarInteractionMode);
+ final int targetType = (isGestureNavigateEnabled
+ && android.provider.Flags.a11yStandaloneGestureEnabled()) ? GESTURE : SOFTWARE;
+
if (isGestureNavigateEnabled) {
final TextView promptPrologue = findViewById(R.id.accessibility_button_prompt_prologue);
promptPrologue.setText(isTouchExploreOn
@@ -78,7 +82,7 @@
: R.string.accessibility_gesture_instructional_text);
}
- mTargets.addAll(getTargets(this, SOFTWARE));
+ mTargets.addAll(getTargets(this, targetType));
final GridView gridview = findViewById(R.id.accessibility_button_chooser_grid);
gridview.setAdapter(new ButtonTargetAdapter(mTargets));
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
index 6256dbc..44c7543 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
@@ -18,7 +18,6 @@
import static com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
-import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getInstalledTargets;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
import static com.android.internal.accessibility.util.AccessibilityUtils.isUserSetupCompleted;
@@ -213,10 +212,7 @@
final boolean isEditMenuMode =
mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT;
final int selectDialogTitleId = R.string.accessibility_select_shortcut_menu_title;
- final int editDialogTitleId =
- mShortcutType == SOFTWARE
- ? R.string.accessibility_edit_shortcut_menu_button_title
- : R.string.accessibility_edit_shortcut_menu_volume_title;
+ final int editDialogTitleId = R.string.accessibility_edit_shortcut_menu_volume_title;
mMenuDialog.setTitle(getString(isEditMenuMode ? editDialogTitleId : selectDialogTitleId));
mMenuDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
index ec90dd2..a753110 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
@@ -16,6 +16,7 @@
package com.android.internal.accessibility.dialog;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
import static com.android.internal.accessibility.util.ShortcutUtils.optInValueToSettings;
@@ -197,6 +198,9 @@
@VisibleForTesting
public static boolean isRecognizedShortcutType(@UserShortcutType int shortcutType) {
int mask = SOFTWARE | HARDWARE;
+ if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
+ mask = mask | GESTURE;
+ }
return (shortcutType != 0 && (shortcutType & mask) == shortcutType);
}
}
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
index 8e18f84..9d66461 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
@@ -23,6 +23,7 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
@@ -247,6 +248,8 @@
} else {
return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
}
+ case GESTURE:
+ return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_GESTURE;
case HARDWARE:
return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY;
case QUICK_SETTINGS:
diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
index 6b0ca9f..48f86ff 100644
--- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
+++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
@@ -166,6 +166,8 @@
switch (type) {
case UserShortcutType.SOFTWARE:
return Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
+ case UserShortcutType.GESTURE:
+ return Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS;
case UserShortcutType.HARDWARE:
return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
case UserShortcutType.TRIPLETAP:
@@ -190,6 +192,7 @@
public static int convertToType(String key) {
return switch (key) {
case Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS -> UserShortcutType.SOFTWARE;
+ case Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS -> UserShortcutType.GESTURE;
case Settings.Secure.ACCESSIBILITY_QS_TARGETS -> UserShortcutType.QUICK_SETTINGS;
case Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE -> UserShortcutType.HARDWARE;
case Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED ->
diff --git a/core/java/com/android/internal/protolog/common/ProtoLog.java b/core/java/com/android/internal/protolog/ProtoLog.java
similarity index 94%
rename from core/java/com/android/internal/protolog/common/ProtoLog.java
rename to core/java/com/android/internal/protolog/ProtoLog.java
index 8149cd5..0118c05 100644
--- a/core/java/com/android/internal/protolog/common/ProtoLog.java
+++ b/core/java/com/android/internal/protolog/ProtoLog.java
@@ -14,7 +14,11 @@
* limitations under the License.
*/
-package com.android.internal.protolog.common;
+package com.android.internal.protolog;
+
+import com.android.internal.protolog.common.IProtoLog;
+import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.LogLevel;
/**
* ProtoLog API - exposes static logging methods. Usage of this API is similar
@@ -35,7 +39,9 @@
* Methods in this class are stubs, that are replaced by optimised versions by the ProtoLogTool
* during build.
*/
+// LINT.IfChange
public class ProtoLog {
+// LINT.ThenChange(frameworks/base/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt)
// Needs to be set directly otherwise the protologtool tries to transform the method call
public static boolean REQUIRE_PROTOLOGTOOL = true;
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index e44c727..565d584 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -62,7 +62,7 @@
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
- android:layout_toStartOf="@id/expand_button"
+ android:layout_toStartOf="@id/notification_buttons_column"
android:layout_alignWithParentIfMissing="true"
android:clipChildren="false"
android:gravity="center_vertical"
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index e983427..61c7a8c 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -424,4 +424,11 @@
<bool name="config_dropboxmanager_persistent_logging_enabled">false</bool>
<java-symbol type="bool" name="config_dropboxmanager_persistent_logging_enabled" />
+ <!-- Telephony satellite gateway class name for handling carrier roaming to satellite is using ESOS messaging. -->
+ <string name="config_satellite_carrier_roaming_esos_provisioned_class" translatable="false"></string>
+ <java-symbol type="string" name="config_satellite_carrier_roaming_esos_provisioned_class" />
+
+ <!-- Telephony satellite gateway intent for handling carrier roaming to satellite is using ESOS messaging. -->
+ <string name="config_satellite_carrier_roaming_esos_provisioned_intent_action" translatable="false"></string>
+ <java-symbol type="string" name="config_satellite_carrier_roaming_esos_provisioned_intent_action" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f696e872..6b71f97 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -722,9 +722,6 @@
<!-- label for screenshot item in power menu [CHAR LIMIT=24]-->
<string name="global_action_screenshot">Screenshot</string>
- <!-- description for mandatory biometrics prompt -->
- <string name="identity_check_biometric_prompt_description">This is needed since Identity Check is on</string>
-
<!-- Take bug report menu title [CHAR LIMIT=30] -->
<string name="bugreport_title">Bug report</string>
<!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7a51abc..7d50d22 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1927,7 +1927,6 @@
<java-symbol type="string" name="global_action_voice_assist" />
<java-symbol type="string" name="global_action_assist" />
<java-symbol type="string" name="global_action_screenshot" />
- <java-symbol type="string" name="identity_check_biometric_prompt_description" />
<java-symbol type="string" name="invalidPuk" />
<java-symbol type="string" name="lockscreen_carrier_default" />
<java-symbol type="style" name="Animation.LockScreen" />
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityTargetTest.java b/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityTargetTest.java
index 389b677..f01ac6f 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityTargetTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/dialog/AccessibilityTargetTest.java
@@ -16,15 +16,22 @@
package com.android.internal.accessibility.dialog;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
import static com.google.common.truth.Truth.assertThat;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.provider.Flags;
+
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.accessibility.common.ShortcutConstants;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,9 +39,13 @@
@RunWith(AndroidJUnit4.class)
public class AccessibilityTargetTest {
+ @Rule
+ public SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final int[] EXPECTED_TYPES = { HARDWARE, SOFTWARE };
+ private static final int[] EXPECTED_TYPES_GESTURE = { HARDWARE, SOFTWARE, GESTURE };
@Test
+ @DisableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
public void isRecognizedShortcutType_expectedType_isTrue() {
for (int type : EXPECTED_TYPES) {
assertThat(AccessibilityTarget.isRecognizedShortcutType(type)).isTrue();
@@ -42,6 +53,7 @@
}
@Test
+ @DisableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
public void isRecognizedShortcutType_notExpectedType_isFalse() {
for (int type: ShortcutConstants.USER_SHORTCUT_TYPES) {
if (IntStream.of(EXPECTED_TYPES).noneMatch(x -> x == type)) {
@@ -49,4 +61,28 @@
}
}
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
+ public void isRecognizedShortcutType_expectedType_gestureIncluded_isTrue() {
+ for (int type : EXPECTED_TYPES_GESTURE) {
+ if (!AccessibilityTarget.isRecognizedShortcutType(type)) {
+ throw new AssertionError(
+ "Shortcut type " + type + " should be recognized");
+ }
+ }
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
+ public void isRecognizedShortcutType_notExpectedType_gestureIncluded_isFalse() {
+ for (int type: ShortcutConstants.USER_SHORTCUT_TYPES) {
+ if (IntStream.of(EXPECTED_TYPES_GESTURE).noneMatch(x -> x == type)) {
+ if (AccessibilityTarget.isRecognizedShortcutType(type)) {
+ throw new AssertionError(
+ "Shortcut type " + type + " should not be recognized");
+ }
+ }
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java b/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java
index 928fce9..8bebc62 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/util/ShortcutUtilsTest.java
@@ -20,6 +20,8 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_MAGNIFICATION_CONTROLLER;
import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
import static com.google.common.truth.Truth.assertThat;
@@ -99,8 +101,7 @@
public void getShortcutTargets_softwareShortcutNoService_emptyResult() {
assertThat(
ShortcutUtils.getShortcutTargetsFromSettings(
- mContext,
- ShortcutConstants.UserShortcutType.SOFTWARE, mDefaultUserId)
+ mContext, SOFTWARE, mDefaultUserId)
).isEmpty();
}
@@ -114,13 +115,21 @@
}
@Test
+ public void getShortcutTargets_gestureShortcutNoService_emptyResult() {
+ assertThat(
+ ShortcutUtils.getShortcutTargetsFromSettings(
+ mContext, GESTURE, mDefaultUserId)
+ ).isEmpty();
+ }
+
+ @Test
public void getShortcutTargets_softwareShortcut1Service_return1Service() {
setupShortcutTargets(ONE_COMPONENT, Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
setupShortcutTargets(TWO_COMPONENTS, Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
assertThat(
ShortcutUtils.getShortcutTargetsFromSettings(
- mContext, ShortcutConstants.UserShortcutType.SOFTWARE,
+ mContext, SOFTWARE,
mDefaultUserId)
).containsExactlyElementsIn(ONE_COMPONENT);
}
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index c573cf4a..a115c65 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -40,6 +40,7 @@
<permission name="android.permission.MASTER_CLEAR"/>
<permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
<permission name="android.permission.MODIFY_AUDIO_ROUTING" />
+ <permission name="android.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED" />
<permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
@@ -92,6 +93,5 @@
<permission name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS" />
<permission name="android.permission.CONTROL_UI_TRACING" />
<permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND" />
- <permission name="android.permission.SET_BIOMETRIC_DIALOG_ADVANCED" />
</privapp-permissions>
</permissions>
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
index f9a6caf..612b387 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -17,6 +17,7 @@
package androidx.window.extensions.embedding;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.window.TaskFragmentAnimationParams.DEFAULT_ANIMATION_BACKGROUND_COLOR;
import static android.window.TaskFragmentOperation.OP_TYPE_REORDER_TO_FRONT;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_ANIMATION_PARAMS;
import static android.window.TaskFragmentOperation.OP_TYPE_SET_DIM_ON_TASK;
@@ -29,6 +30,7 @@
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishPrimaryWithSecondary;
import static androidx.window.extensions.embedding.SplitContainer.shouldFinishSecondaryWithPrimary;
+import android.annotation.ColorInt;
import android.app.Activity;
import android.app.WindowConfiguration.WindowingMode;
import android.content.Intent;
@@ -391,13 +393,22 @@
if (splitAttributes == null) {
return TaskFragmentAnimationParams.DEFAULT;
}
+ final int animationBackgroundColor = getAnimationBackgroundColor(splitAttributes);
+ TaskFragmentAnimationParams.Builder builder = new TaskFragmentAnimationParams.Builder();
+ if (animationBackgroundColor != DEFAULT_ANIMATION_BACKGROUND_COLOR) {
+ builder.setAnimationBackgroundColor(animationBackgroundColor);
+ }
+ // TODO(b/293658614): Allow setting custom open/close/changeAnimationResId.
+ return builder.build();
+ }
+
+ @ColorInt
+ private static int getAnimationBackgroundColor(@NonNull SplitAttributes splitAttributes) {
+ int animationBackgroundColor = DEFAULT_ANIMATION_BACKGROUND_COLOR;
final AnimationBackground animationBackground = splitAttributes.getAnimationBackground();
if (animationBackground instanceof AnimationBackground.ColorBackground colorBackground) {
- return new TaskFragmentAnimationParams.Builder()
- .setAnimationBackgroundColor(colorBackground.getColor())
- .build();
- } else {
- return TaskFragmentAnimationParams.DEFAULT;
+ animationBackgroundColor = colorBackground.getColor();
}
+ return animationBackgroundColor;
}
}
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 25d3067..1e68241 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -88,7 +88,7 @@
],
tools: ["protologtool"],
cmd: "$(location protologtool) transform-protolog-calls " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
"--loggroups-jar $(location :wm_shell_protolog-groups) " +
"--viewer-config-file-path /system_ext/etc/wmshell.protolog.pb " +
@@ -107,7 +107,7 @@
],
tools: ["protologtool"],
cmd: "$(location protologtool) generate-viewer-config " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
"--loggroups-jar $(location :wm_shell_protolog-groups) " +
"--viewer-config-type json " +
@@ -124,7 +124,7 @@
],
tools: ["protologtool"],
cmd: "$(location protologtool) generate-viewer-config " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
"--loggroups-jar $(location :wm_shell_protolog-groups) " +
"--viewer-config-type proto " +
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/OWNERS b/libs/WindowManager/Shell/multivalentScreenshotTests/OWNERS
new file mode 100644
index 0000000..dc11241
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/OWNERS
@@ -0,0 +1,4 @@
+atsjenk@google.com
+liranb@google.com
+madym@google.com
+mpodolian@google.com
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png
index eb28881..027b28e 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/dark_portrait_bubbles_education.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png
index eb28881..027b28e 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/onDevice/phone/light_portrait_bubbles_education.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
index 9e1440d..ae60d8b 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
@@ -27,7 +27,7 @@
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.R
import com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT
import com.android.wm.shell.common.bubbles.BubbleBarLocation
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt
index 327e205..5e67333 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleStackViewTest.kt
@@ -32,7 +32,7 @@
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.internal.logging.testing.UiEventLoggerFake
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.launcher3.icons.BubbleIconFactory
import com.android.wm.shell.Flags
import com.android.wm.shell.R
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt
index ace2c13..935d129 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleExpandedViewPinControllerTest.kt
@@ -27,7 +27,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.R
import com.android.wm.shell.bubbles.BubblePositioner
import com.android.wm.shell.bubbles.DeviceConfig
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java
index 4876f32..92084e4 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/DesktopModeStatus.java
@@ -16,9 +16,13 @@
package com.android.wm.shell.shared;
+import static android.provider.Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES;
+
import android.annotation.NonNull;
import android.content.Context;
import android.os.SystemProperties;
+import android.provider.Settings;
+import android.util.Log;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -29,6 +33,8 @@
*/
public class DesktopModeStatus {
+ private static final String TAG = "DesktopModeStatus";
+
/**
* Flag to indicate whether task resizing is veiled.
*/
@@ -98,11 +104,12 @@
"persist.wm.debug.desktop_max_task_limit", DEFAULT_MAX_TASK_LIMIT);
/**
- * Return {@code true} if desktop windowing is enabled. Only to be used for testing. Callers
- * should use {@link #canEnterDesktopMode(Context)} to query the state of desktop windowing.
+ * Return {@code true} if desktop windowing flag is enabled. Only to be used for testing.
+ * Callers should use {@link #canEnterDesktopMode(Context)} to query the state of desktop
+ * windowing.
*/
@VisibleForTesting
- public static boolean isEnabled() {
+ public static boolean isDesktopModeFlagEnabled() {
return Flags.enableDesktopWindowingMode();
}
@@ -120,7 +127,7 @@
*/
public static boolean useWindowShadow(boolean isFocusedWindow) {
return USE_WINDOW_SHADOWS
- || (USE_WINDOW_SHADOWS_FOCUSED_WINDOW && isFocusedWindow);
+ || (USE_WINDOW_SHADOWS_FOCUSED_WINDOW && isFocusedWindow);
}
/**
@@ -154,10 +161,36 @@
}
/**
+ * Return {@code true} if desktop mode dev option should be shown on current device
+ */
+ public static boolean canShowDesktopModeDevOption(@NonNull Context context) {
+ return isDeviceEligibleForDesktopMode(context) && Flags.showDesktopWindowingDevOption();
+ }
+
+ /** Returns if desktop mode dev option should be enabled if there is no user override. */
+ public static boolean shouldDevOptionBeEnabledByDefault() {
+ return isDesktopModeFlagEnabled();
+ }
+
+ /**
* Return {@code true} if desktop mode is enabled and can be entered on the current device.
*/
public static boolean canEnterDesktopMode(@NonNull Context context) {
- return (!enforceDeviceRestrictions() || isDesktopModeSupported(context)) && isEnabled();
+ if (!isDeviceEligibleForDesktopMode(context)) return false;
+
+ // If dev option has ever been manually toggled by the user, return its value
+ // TODO(b/348193756) : Move the logic for DW override based on toggle overides to a common
+ // infrastructure and add caching for the computation
+ int defaultOverrideState = -1;
+ int toggleState = Settings.Global.getInt(context.getContentResolver(),
+ DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES, defaultOverrideState);
+ if (toggleState != defaultOverrideState) {
+ Log.d(TAG, "Using Desktop mode dev option overridden state");
+ return toggleState != 0;
+ }
+
+ // Return Desktop windowing flag value
+ return isDesktopModeFlagEnabled();
}
/**
@@ -181,4 +214,11 @@
return DESKTOP_DENSITY_OVERRIDE >= DESKTOP_DENSITY_MIN
&& DESKTOP_DENSITY_OVERRIDE <= DESKTOP_DENSITY_MAX;
}
+
+ /**
+ * Return {@code true} if desktop mode is unrestricted and is supported in the device.
+ */
+ private static boolean isDeviceEligibleForDesktopMode(@NonNull Context context) {
+ return !enforceDeviceRestrictions() || isDesktopModeSupported(context);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
index ef9bf00..514307f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
@@ -19,7 +19,7 @@
import com.android.internal.protolog.LegacyProtoLogImpl;
import com.android.internal.protolog.common.ILogger;
import com.android.internal.protolog.common.IProtoLog;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellInit;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
index 2e5448a..b9bf136 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java
@@ -29,7 +29,7 @@
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.sysui.ShellInit;
import java.io.PrintWriter;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
index 5143d41..9f01316 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java
@@ -38,7 +38,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.sysui.ShellInit;
import java.io.PrintWriter;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index bebfa90..ebdea1b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -52,7 +52,7 @@
import android.window.TaskOrganizer;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 7041ea3..ece0271 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -59,7 +59,7 @@
import android.window.IOnBackInvokedCallback;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.LatencyTracker;
import com.android.internal.view.AppearanceRegion;
import com.android.wm.shell.R;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
index c9d3dbd..4f04c5c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt
@@ -48,7 +48,7 @@
import com.android.internal.jank.Cuj
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.internal.policy.SystemBarUtils
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.animation.Interpolators
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
index 381914a5..103a654 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
@@ -49,7 +49,7 @@
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.policy.SystemBarUtils;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.shared.annotations.ShellMainThread;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
index c738ce5..e266e2c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt
@@ -28,7 +28,7 @@
import android.window.BackNavigationInfo
import com.android.internal.R
import com.android.internal.policy.TransitionAnimation
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.protolog.ShellProtoLogGroup
import com.android.wm.shell.shared.annotations.ShellMainThread
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 2aefc64..7dbbb04 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -48,7 +48,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index c853301..e36f6e6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -84,7 +84,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.CollectionUtils;
import com.android.launcher3.icons.BubbleIconFactory;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index 761e025..4e6c517 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -35,7 +35,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.Bubbles.DismissReason;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index c7ccd50..f7a5c27 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -67,7 +67,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.common.AlphaOptimizedButton;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
index 18e04d1..bf98ef8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
@@ -42,7 +42,7 @@
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ContrastColorUtil;
import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 2382545..0cf187b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -29,7 +29,7 @@
import androidx.annotation.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconNormalizer;
import com.android.wm.shell.R;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 09bec8c..f93f19d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -78,7 +78,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
index 0b66bcb..c79d9c4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java
@@ -35,7 +35,7 @@
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.taskview.TaskView;
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java
index 1375684..9429c9e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarGestureTracker.java
@@ -29,7 +29,7 @@
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.bubbles.BubblesNavBarMotionEventHandler.MotionEventListener;
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java
index b7107f0..d4f53ab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblesNavBarMotionEventHandler.java
@@ -28,7 +28,7 @@
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
/**
* Handles {@link MotionEvent}s for bubbles that begin in the nav bar area
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
index aa4129a..fbef6b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedViewAnimationControllerImpl.java
@@ -38,7 +38,7 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.animation.FlingAnimationUtils;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.bubbles.BubbleExpandedView;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
index e261d92..f792392 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
@@ -28,7 +28,7 @@
import android.window.WindowContainerTransactionCallback;
import android.window.WindowOrganizer;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.transition.LegacyTransitions;
import java.util.ArrayList;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
index 43c92ca..43f9cb98 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
@@ -32,7 +32,7 @@
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.sysui.ShellInit;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java
index 58007b5..8e026f0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsAlgorithm.java
@@ -27,7 +27,7 @@
import android.util.Size;
import android.view.Gravity;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
index 7ceaaea..64a1b0c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
@@ -32,7 +32,7 @@
import android.util.Size;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.TriConsumer;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipPerfHintController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipPerfHintController.java
index c421dec..b9c698e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipPerfHintController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipPerfHintController.java
@@ -26,7 +26,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.shared.annotations.ShellMainThread;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
index 3e9366f..dcf84d9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt
@@ -30,7 +30,7 @@
import android.util.Pair
import android.util.TypedValue
import android.window.TaskSnapshot
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.Flags
import com.android.wm.shell.protolog.ShellProtoLogGroup
import kotlin.math.abs
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index 2234041..3ad60e7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -54,7 +54,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 8ced76f..d3c349f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -59,7 +59,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
index e710560..a67dee3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeLoggerTransitionObserver.kt
@@ -35,7 +35,7 @@
import androidx.core.util.putAll
import com.android.internal.logging.InstanceId
import com.android.internal.logging.InstanceIdSequence
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
index 217b1d3..1bf1259 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeUtils.kt
@@ -19,6 +19,8 @@
package com.android.wm.shell.desktopmode
import android.app.ActivityManager.RunningTaskInfo
+import android.app.TaskInfo
+import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
import android.content.pm.ActivityInfo.isFixedOrientationLandscape
import android.content.pm.ActivityInfo.isFixedOrientationPortrait
import android.content.res.Configuration.ORIENTATION_LANDSCAPE
@@ -105,7 +107,7 @@
* Calculates the largest size that can fit in a given area while maintaining a specific aspect
* ratio.
*/
-private fun maximumSizeMaintainingAspectRatio(
+fun maximumSizeMaintainingAspectRatio(
taskInfo: RunningTaskInfo,
targetArea: Size,
aspectRatio: Float
@@ -114,7 +116,8 @@
val targetWidth = targetArea.width
val finalHeight: Int
val finalWidth: Int
- if (isFixedOrientationPortrait(taskInfo.topActivityInfo!!.screenOrientation)) {
+ // Get orientation either through top activity or task's orientation
+ if (taskInfo.hasPortraitTopActivity()) {
val tempWidth = (targetHeight / aspectRatio).toInt()
if (tempWidth <= targetWidth) {
finalHeight = targetHeight
@@ -137,7 +140,7 @@
}
/** Calculates the aspect ratio of an activity from its fullscreen bounds. */
-private fun calculateAspectRatio(taskInfo: RunningTaskInfo): Float {
+fun calculateAspectRatio(taskInfo: RunningTaskInfo): Float {
if (taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed) {
val appLetterboxWidth = taskInfo.appCompatTaskInfo.topActivityLetterboxWidth
val appLetterboxHeight = taskInfo.appCompatTaskInfo.topActivityLetterboxHeight
@@ -171,3 +174,41 @@
desiredSize.height + heightOffset
)
}
+
+/**
+ * Adjusts bounds to be positioned in the middle of the area provided, not necessarily the
+ * entire screen, as area can be offset by left and top start.
+ */
+fun centerInArea(desiredSize: Size, areaBounds: Rect, leftStart: Int, topStart: Int): Rect {
+ val heightOffset = (areaBounds.height() - desiredSize.height) / 2
+ val widthOffset = (areaBounds.width() - desiredSize.width) / 2
+
+ val newLeft = leftStart + widthOffset
+ val newTop = topStart + heightOffset
+ val newRight = newLeft + desiredSize.width
+ val newBottom = newTop + desiredSize.height
+
+ return Rect(newLeft, newTop, newRight, newBottom)
+}
+
+fun TaskInfo.hasPortraitTopActivity(): Boolean {
+ val topActivityScreenOrientation =
+ topActivityInfo?.screenOrientation ?: SCREEN_ORIENTATION_UNSPECIFIED
+ val appBounds = configuration.windowConfiguration.appBounds
+
+ return when {
+ // First check if activity has portrait screen orientation
+ topActivityScreenOrientation != SCREEN_ORIENTATION_UNSPECIFIED -> {
+ isFixedOrientationPortrait(topActivityScreenOrientation)
+ }
+
+ // Then check if the activity is portrait when letterboxed
+ appCompatTaskInfo.topActivityBoundsLetterboxed -> appCompatTaskInfo.isTopActivityPillarboxed
+
+ // Then check if the activity is portrait
+ appBounds != null -> appBounds.height() > appBounds.width()
+
+ // Otherwise just take the orientation of the task
+ else -> isFixedOrientationPortrait(configuration.orientation)
+ }
+}
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 5813f85..d8e8c57 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
@@ -36,6 +36,7 @@
import android.graphics.Region
import android.os.IBinder
import android.os.SystemProperties
+import android.util.Size
import android.view.Display.DEFAULT_DISPLAY
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CHANGE
@@ -649,13 +650,21 @@
fun toggleDesktopTaskSize(taskInfo: RunningTaskInfo) {
val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return
- val stableBounds = Rect()
- displayLayout.getStableBounds(stableBounds)
+ val stableBounds = Rect().apply { displayLayout.getStableBounds(this) }
+ val currentTaskBounds = taskInfo.configuration.windowConfiguration.bounds
val destinationBounds = Rect()
- if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) {
- // The desktop task is currently occupying the whole stable bounds. If the bounds
- // before the task was toggled to stable bounds were saved, toggle the task to those
- // bounds. Otherwise, toggle to the default bounds.
+
+ val isMaximized = if (taskInfo.isResizeable) {
+ currentTaskBounds == stableBounds
+ } else {
+ currentTaskBounds.width() == stableBounds.width()
+ || currentTaskBounds.height() == stableBounds.height()
+ }
+
+ if (isMaximized) {
+ // The desktop task is at the maximized width and/or height of the stable bounds.
+ // If the task's pre-maximize stable bounds were saved, toggle the task to those bounds.
+ // Otherwise, toggle to the default bounds.
val taskBoundsBeforeMaximize =
desktopModeTaskRepository.removeBoundsBeforeMaximize(taskInfo.taskId)
if (taskBoundsBeforeMaximize != null) {
@@ -670,9 +679,20 @@
} else {
// Save current bounds so that task can be restored back to original bounds if necessary
// and toggle to the stable bounds.
- val taskBounds = taskInfo.configuration.windowConfiguration.bounds
- desktopModeTaskRepository.saveBoundsBeforeMaximize(taskInfo.taskId, taskBounds)
- destinationBounds.set(stableBounds)
+ desktopModeTaskRepository.saveBoundsBeforeMaximize(taskInfo.taskId, currentTaskBounds)
+
+ if (taskInfo.isResizeable) {
+ // if resizable then expand to entire stable bounds (full display minus insets)
+ destinationBounds.set(stableBounds)
+ } else {
+ // if non-resizable then calculate max bounds according to aspect ratio
+ val activityAspectRatio = calculateAspectRatio(taskInfo)
+ val newSize = maximumSizeMaintainingAspectRatio(taskInfo,
+ Size(stableBounds.width(), stableBounds.height()), activityAspectRatio)
+ val newBounds = centerInArea(
+ newSize, stableBounds, stableBounds.left, stableBounds.top)
+ destinationBounds.set(newBounds)
+ }
}
val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index a4813a3..b3c3a3d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -59,7 +59,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
index b1882fc..9c7476d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java
@@ -66,7 +66,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.internal.logging.InstanceId;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index 5df83be..910175e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -20,7 +20,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.content.pm.ActivityInfo.CONFIG_ASSETS_PATHS;
import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
@@ -56,7 +55,7 @@
import androidx.annotation.NonNull;
import com.android.internal.logging.InstanceId;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
index 41a50b1..3bedef2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java
@@ -30,7 +30,7 @@
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index 2ccadb8..b6b49a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -38,7 +38,7 @@
import androidx.annotation.Nullable;
import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/GlobalDragListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/GlobalDragListener.kt
index 31214eb..ffcfe644 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/GlobalDragListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/GlobalDragListener.kt
@@ -25,7 +25,7 @@
import android.window.IGlobalDragListener
import android.window.IUnhandledDragCallback
import androidx.annotation.VisibleForTesting
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.protolog.ShellProtoLogGroup
import java.util.function.Consumer
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index b48aee5..1641668 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -25,7 +25,7 @@
import android.util.SparseArray;
import android.view.SurfaceControl;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
index 2626e73..d2ceb67 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
@@ -27,7 +27,7 @@
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
index cd478e5..333c75f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java
@@ -49,7 +49,7 @@
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index 0a3c15b..dc449d1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -37,7 +37,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.pip.PipUtils;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 3fae370..6a6e2ec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -73,7 +73,7 @@
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators;
@@ -636,6 +636,13 @@
return;
}
+ // bail early if leash is null
+ if (mLeash == null) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "exitPip: leash is null");
+ return;
+ }
+
final Rect destinationBounds = new Rect(getExitDestinationBounds());
final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index f3a8fbf..e5633de 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -63,7 +63,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index a7c47f9..8d36db9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -41,7 +41,7 @@
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
@@ -127,8 +127,10 @@
/**
* Called when the Shell wants to start resizing Pip transition/animation.
+ *
+ * @param duration the suggested duration for resize animation.
*/
- public void startResizeTransition(WindowContainerTransaction wct) {
+ public void startResizeTransition(WindowContainerTransaction wct, int duration) {
// Default implementation does nothing.
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 0169e8c..c7369a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -32,7 +32,7 @@
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.pip.PipBoundsState;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 448d4f5..d1d8275 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -59,7 +59,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayChangeController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
index f6cab48..d1978c3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
@@ -28,7 +28,7 @@
import android.view.InputChannel;
import android.view.InputEvent;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 15342be..c189642 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -59,7 +59,7 @@
import android.widget.FrameLayout;
import android.widget.LinearLayout;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.ShellExecutor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
index f5bd006..df3803d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMotionHelper.java
@@ -34,7 +34,7 @@
import android.graphics.Rect;
import android.os.Debug;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.FloatProperties;
import com.android.wm.shell.common.FloatingContentCoordinator;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index d8ac8e9..9c4e723 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -48,7 +48,7 @@
import android.view.accessibility.AccessibilityWindowInfo;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
index 5d858fa..cb82db6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchState.java
@@ -23,7 +23,7 @@
import android.view.ViewConfiguration;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
index 6b890c4..50d22ad 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipActionsProvider.java
@@ -33,7 +33,7 @@
import android.content.Context;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.pip.PipMediaController;
import com.android.wm.shell.common.pip.PipUtils;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBackgroundView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBackgroundView.java
index 0221db8..eb7a10c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBackgroundView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBackgroundView.java
@@ -28,7 +28,7 @@
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
index 72c0cd7..188c35f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
@@ -33,7 +33,7 @@
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
index 8a215b4..1afb470 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
@@ -26,7 +26,7 @@
import android.os.Handler;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index b6a7c56..0ed5079 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -39,7 +39,7 @@
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
index 977aad4..327ceef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
@@ -27,7 +27,7 @@
import android.os.Bundle;
import android.os.Handler;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.TvWindowMenuActionButton;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 6b5bdd2..e74870d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -37,7 +37,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.pip.PipMenuController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java
index adc03cf..eabf1b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java
@@ -39,7 +39,7 @@
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import java.util.Arrays;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
index 4a767ef..c7704f0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -50,7 +50,7 @@
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.widget.LinearLayoutManager;
import com.android.internal.widget.RecyclerView;
import com.android.wm.shell.R;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
index 54e162b..ce50792 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java
@@ -33,7 +33,7 @@
import android.text.TextUtils;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ImageUtils;
import com.android.wm.shell.R;
import com.android.wm.shell.common.pip.PipMediaController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
index ca0d61f..7a0e669 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
@@ -62,7 +62,7 @@
import androidx.annotation.Nullable;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java
index 5c561fe..88f9e4c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java
@@ -47,9 +47,17 @@
@Nullable
private Runnable mAnimationEndCallback;
private RectEvaluator mRectEvaluator;
+
+ // Bounds relative to which scaling/cropping must be done.
private final Rect mBaseBounds = new Rect();
+
+ // Bounds to animate from.
private final Rect mStartBounds = new Rect();
+
+ // Target bounds.
private final Rect mEndBounds = new Rect();
+
+ // Bounds updated by the evaluator as animator is running.
private final Rect mAnimatedRect = new Rect();
private final float mDelta;
@@ -84,7 +92,6 @@
addListener(this);
addUpdateListener(this);
setEvaluator(mRectEvaluator);
- // TODO: change this
setDuration(duration);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
index 6e36a32..9cfe162 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
@@ -32,7 +32,7 @@
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.pip.PipBoundsState;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index fc0d36d..06adad6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -36,7 +36,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.Preconditions;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -352,6 +352,7 @@
mPipBoundsAlgorithm.dump(pw, innerPrefix);
mPipBoundsState.dump(pw, innerPrefix);
mPipDisplayLayoutState.dump(pw, innerPrefix);
+ mPipTransitionState.dump(pw, innerPrefix);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java
index b757b00..ffda56d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java
@@ -28,7 +28,7 @@
import android.view.InputChannel;
import android.view.InputEvent;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
index 42b8e9f..c54e4cd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
@@ -59,7 +59,7 @@
import android.widget.FrameLayout;
import android.widget.LinearLayout;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.ShellExecutor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
index 495cd00..e277a8d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.pip2.phone;
+import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY;
import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_NO_BOUNCY;
import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW;
import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_MEDIUM;
@@ -25,6 +26,7 @@
import static com.android.wm.shell.common.pip.PipBoundsState.STASH_TYPE_RIGHT;
import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_DISMISS;
import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_NONE;
+import static com.android.wm.shell.pip2.phone.PipTransition.ANIMATING_BOUNDS_CHANGE_DURATION;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -35,7 +37,8 @@
import android.os.Debug;
import android.view.SurfaceControl;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
+import com.android.internal.util.Preconditions;
import com.android.wm.shell.R;
import com.android.wm.shell.animation.FloatProperties;
import com.android.wm.shell.common.FloatingContentCoordinator;
@@ -45,6 +48,7 @@
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipPerfHintController;
import com.android.wm.shell.common.pip.PipSnapAlgorithm;
+import com.android.wm.shell.pip2.animation.PipResizeAnimator;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
@@ -62,6 +66,7 @@
PipTransitionState.PipTransitionStateChangedListener {
private static final String TAG = "PipMotionHelper";
private static final String FLING_BOUNDS_CHANGE = "fling_bounds_change";
+ private static final String ANIMATING_BOUNDS_CHANGE = "animating_bounds_change";
private static final boolean DEBUG = false;
private static final int SHRINK_STACK_FROM_MENU_DURATION = 250;
@@ -113,7 +118,7 @@
/** SpringConfig to use for fling-then-spring animations. */
private final PhysicsAnimator.SpringConfig mSpringConfig =
- new PhysicsAnimator.SpringConfig(700f, DAMPING_RATIO_NO_BOUNCY);
+ new PhysicsAnimator.SpringConfig(300f, DAMPING_RATIO_LOW_BOUNCY);
/** SpringConfig used for animating into the dismiss region, matches the one in
* {@link MagnetizedObject}. */
@@ -152,9 +157,16 @@
private boolean mDismissalPending = false;
/**
- * Set to true if bounds change transition has been scheduled from PipMotionHelper.
+ * Set to true if bounds change transition has been scheduled from PipMotionHelper
+ * after animating is over.
*/
- private boolean mWaitingForBoundsChangeTransition = false;
+ private boolean mWaitingForFlingTransition = false;
+
+ /**
+ * Set to true if bounds change transition has been scheduled from PipMotionHelper,
+ * and if the animation is supposed to run while transition is playing.
+ */
+ private boolean mWaitingToPlayBoundsChangeTransition = false;
/**
* Gets set in {@link #animateToExpandedState(Rect, Rect, Rect, Runnable)}, this callback is
@@ -634,6 +646,9 @@
// The physics animation ended, though we may not necessarily be done animating, such as
// when we're still dragging after moving out of the magnetic target.
if (!mDismissalPending && !mSpringingToTouch && !mMagnetizedPip.getObjectStuckToTarget()) {
+ // Update the earlier estimate on bounds we are animating towards, since physics
+ // animator is non-deterministic.
+ setAnimatingToBounds(mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
// do not schedule resize if PiP is dismissing, which may cause app re-open to
// mBounds instead of its normal bounds.
Bundle extra = new Bundle();
@@ -673,6 +688,11 @@
* Directly resizes the PiP to the given {@param bounds}.
*/
private void resizeAndAnimatePipUnchecked(Rect toBounds, int duration) {
+ if (mPipBoundsState.getMotionBoundsState().isInMotion()) {
+ // Do not carry out any resizing if we are dragging or physics animator is running.
+ return;
+ }
+
if (DEBUG) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: resizeAndAnimatePipUnchecked: toBounds=%s"
@@ -682,10 +702,11 @@
// Intentionally resize here even if the current bounds match the destination bounds.
// This is so all the proper callbacks are performed.
-
- // mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration,
- // TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND, null /* updateBoundsCallback */);
- // setAnimatingToBounds(toBounds);
+ setAnimatingToBounds(toBounds);
+ Bundle extra = new Bundle();
+ extra.putBoolean(ANIMATING_BOUNDS_CHANGE, true);
+ extra.putInt(ANIMATING_BOUNDS_CHANGE_DURATION, duration);
+ mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra);
}
@Override
@@ -694,7 +715,11 @@
@Nullable Bundle extra) {
switch (newState) {
case PipTransitionState.SCHEDULED_BOUNDS_CHANGE:
- if (!extra.getBoolean(FLING_BOUNDS_CHANGE)) break;
+ mWaitingForFlingTransition = extra.getBoolean(FLING_BOUNDS_CHANGE);
+ mWaitingToPlayBoundsChangeTransition = extra.getBoolean(ANIMATING_BOUNDS_CHANGE);
+ if (!mWaitingForFlingTransition && !mWaitingToPlayBoundsChangeTransition) {
+ break;
+ }
if (mPipBoundsState.getBounds().equals(
mPipBoundsState.getMotionBoundsState().getBoundsInMotion())) {
@@ -709,30 +734,30 @@
break;
}
- // If touch is turned off and we are in a fling animation, schedule a transition.
- mWaitingForBoundsChangeTransition = true;
+ // Delay config until the end, if we are animating after scheduling the transition.
mPipScheduler.scheduleAnimateResizePip(
- mPipBoundsState.getMotionBoundsState().getBoundsInMotion());
+ mPipBoundsState.getMotionBoundsState().getAnimatingToBounds(),
+ mWaitingToPlayBoundsChangeTransition,
+ extra.getInt(ANIMATING_BOUNDS_CHANGE_DURATION,
+ PipTransition.BOUNDS_CHANGE_JUMPCUT_DURATION));
break;
case PipTransitionState.CHANGING_PIP_BOUNDS:
- if (!mWaitingForBoundsChangeTransition) break;
-
- // If bounds change transition was scheduled from this class, handle leash updates.
- mWaitingForBoundsChangeTransition = false;
SurfaceControl.Transaction startTx = extra.getParcelable(
PipTransition.PIP_START_TX, SurfaceControl.Transaction.class);
+ SurfaceControl.Transaction finishTx = extra.getParcelable(
+ PipTransition.PIP_FINISH_TX, SurfaceControl.Transaction.class);
Rect destinationBounds = extra.getParcelable(
PipTransition.PIP_DESTINATION_BOUNDS, Rect.class);
- startTx.setPosition(mPipTransitionState.mPinnedTaskLeash,
- destinationBounds.left, destinationBounds.top);
- startTx.apply();
+ final int duration = extra.getInt(ANIMATING_BOUNDS_CHANGE_DURATION,
+ PipTransition.BOUNDS_CHANGE_JUMPCUT_DURATION);
- // All motion operations have actually finished, so make bounds cache updates.
- settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */);
- cleanUpHighPerfSessionMaybe();
-
- // Signal that the transition is done - should update transition state by default.
- mPipScheduler.scheduleFinishResizePip(false /* configAtEnd */);
+ if (mWaitingForFlingTransition) {
+ mWaitingForFlingTransition = false;
+ handleFlingTransition(startTx, finishTx, destinationBounds);
+ } else if (mWaitingToPlayBoundsChangeTransition) {
+ mWaitingToPlayBoundsChangeTransition = false;
+ startResizeAnimation(startTx, finishTx, destinationBounds, duration);
+ }
break;
case PipTransitionState.EXITING_PIP:
// We need to force finish any local animators if about to leave PiP, to avoid
@@ -740,9 +765,46 @@
if (!mPipBoundsState.getMotionBoundsState().isInMotion()) break;
cancelPhysicsAnimation();
settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */);
+ break;
}
}
+ private void handleFlingTransition(SurfaceControl.Transaction startTx,
+ SurfaceControl.Transaction finishTx, Rect destinationBounds) {
+ startTx.setPosition(mPipTransitionState.mPinnedTaskLeash,
+ destinationBounds.left, destinationBounds.top);
+ startTx.apply();
+
+ // All motion operations have actually finished, so make bounds cache updates.
+ settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */);
+ cleanUpHighPerfSessionMaybe();
+
+ // Signal that the transition is done - should update transition state by default.
+ mPipScheduler.scheduleFinishResizePip(false /* configAtEnd */);
+ }
+
+ private void startResizeAnimation(SurfaceControl.Transaction startTx,
+ SurfaceControl.Transaction finishTx, Rect destinationBounds, int duration) {
+ SurfaceControl pipLeash = mPipTransitionState.mPinnedTaskLeash;
+ Preconditions.checkState(pipLeash != null,
+ "No leash cached by mPipTransitionState=" + mPipTransitionState);
+
+ startTx.setWindowCrop(pipLeash, mPipBoundsState.getBounds().width(),
+ mPipBoundsState.getBounds().height());
+
+ PipResizeAnimator animator = new PipResizeAnimator(mContext, pipLeash,
+ startTx, finishTx, mPipBoundsState.getBounds(), mPipBoundsState.getBounds(),
+ destinationBounds, duration, 0f /* angle */);
+ animator.setAnimationEndCallback(() -> {
+ mPipBoundsState.setBounds(destinationBounds);
+ // All motion operations have actually finished, so make bounds cache updates.
+ cleanUpHighPerfSessionMaybe();
+ // Signal that we are done with resize transition
+ mPipScheduler.scheduleFinishResizePip(true /* configAtEnd */);
+ });
+ animator.start();
+ }
+
private void settlePipBoundsAfterPhysicsAnimation(boolean animatingAfter) {
if (!animatingAfter) {
// The physics animation ended, though we may not necessarily be done animating, such as
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
index 33e80bd..5b0ca18 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.pip2.phone;
import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE;
+import static com.android.wm.shell.pip2.phone.PipTransition.ANIMATING_BOUNDS_CHANGE_DURATION;
import android.annotation.Nullable;
import android.content.Context;
@@ -535,7 +536,8 @@
mWaitingForBoundsChangeTransition = true;
// Schedule PiP resize transition, but delay any config updates until very end.
- mPipScheduler.scheduleAnimateResizePip(mLastResizeBounds, true /* configAtEnd */);
+ mPipScheduler.scheduleAnimateResizePip(mLastResizeBounds,
+ true /* configAtEnd */, PINCH_RESIZE_SNAP_DURATION);
break;
case PipTransitionState.CHANGING_PIP_BOUNDS:
if (!mWaitingForBoundsChangeTransition) break;
@@ -550,12 +552,15 @@
PipTransition.PIP_START_TX, SurfaceControl.Transaction.class);
SurfaceControl.Transaction finishTx = extra.getParcelable(
PipTransition.PIP_FINISH_TX, SurfaceControl.Transaction.class);
+ final int duration = extra.getInt(ANIMATING_BOUNDS_CHANGE_DURATION,
+ PipTransition.BOUNDS_CHANGE_JUMPCUT_DURATION);
+
startTx.setWindowCrop(pipLeash, mPipBoundsState.getBounds().width(),
mPipBoundsState.getBounds().height());
PipResizeAnimator animator = new PipResizeAnimator(mContext, pipLeash,
startTx, finishTx, mPipBoundsState.getBounds(), mStartBoundsAfterRelease,
- mLastResizeBounds, PINCH_RESIZE_SNAP_DURATION, mAngle);
+ mLastResizeBounds, duration, mAngle);
animator.setAnimationEndCallback(() -> {
// All motion operations have actually finished, so make bounds cache updates.
mUpdateResizeBoundsCallback.accept(mLastResizeBounds);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index 9c1e321..ac670cf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -33,7 +33,7 @@
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipUtils;
@@ -162,6 +162,18 @@
* @param configAtEnd true if we are delaying config updates until the transition ends.
*/
public void scheduleAnimateResizePip(Rect toBounds, boolean configAtEnd) {
+ scheduleAnimateResizePip(toBounds, configAtEnd,
+ PipTransition.BOUNDS_CHANGE_JUMPCUT_DURATION);
+ }
+
+ /**
+ * Animates resizing of the pinned stack given the duration.
+ *
+ * @param configAtEnd true if we are delaying config updates until the transition ends.
+ * @param duration the suggested duration to run the animation; the component responsible
+ * for running the animator will get this as an extra.
+ */
+ public void scheduleAnimateResizePip(Rect toBounds, boolean configAtEnd, int duration) {
if (mPipTransitionState.mPipTaskToken == null || !mPipTransitionState.isInPip()) {
return;
}
@@ -170,7 +182,7 @@
if (configAtEnd) {
wct.deferConfigToTransitionEnd(mPipTransitionState.mPipTaskToken);
}
- mPipTransitionController.startResizeTransition(wct);
+ mPipTransitionController.startResizeTransition(wct, duration);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
index 56a465a..0c4ed26 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java
@@ -51,7 +51,7 @@
import android.view.accessibility.AccessibilityWindowInfo;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
@@ -713,15 +713,13 @@
}
}
- private void animateToMaximizedState(Runnable callback) {
- Rect maxMovementBounds = new Rect();
+ private void animateToMaximizedState() {
Rect maxBounds = new Rect(0, 0, mPipBoundsState.getMaxSize().x,
mPipBoundsState.getMaxSize().y);
- mPipBoundsAlgorithm.getMovementBounds(maxBounds, mInsetBounds, maxMovementBounds,
- mIsImeShowing ? mImeHeight : 0);
+
mSavedSnapFraction = mMotionHelper.animateToExpandedState(maxBounds,
- mPipBoundsState.getMovementBounds(), maxMovementBounds,
- callback);
+ getMovementBounds(mPipBoundsState.getBounds()),
+ getMovementBounds(maxBounds), null /* callback */);
}
private void animateToNormalSize(Runnable callback) {
@@ -729,22 +727,20 @@
mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
final Size minMenuSize = mMenuController.getEstimatedMinMenuSize();
- final Rect normalBounds = mPipBoundsState.getNormalBounds();
- final Rect destBounds = mPipBoundsAlgorithm.adjustNormalBoundsToFitMenu(normalBounds,
- minMenuSize);
- Rect restoredMovementBounds = new Rect();
- mPipBoundsAlgorithm.getMovementBounds(destBounds,
- mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
- mSavedSnapFraction = mMotionHelper.animateToExpandedState(destBounds,
- mPipBoundsState.getMovementBounds(), restoredMovementBounds, callback);
+ final Size defaultSize = mSizeSpecSource.getDefaultSize(mPipBoundsState.getAspectRatio());
+ final Rect normalBounds = new Rect(0, 0, defaultSize.getWidth(), defaultSize.getHeight());
+ final Rect adjustedNormalBounds = mPipBoundsAlgorithm.adjustNormalBoundsToFitMenu(
+ normalBounds, minMenuSize);
+
+ mSavedSnapFraction = mMotionHelper.animateToExpandedState(adjustedNormalBounds,
+ getMovementBounds(mPipBoundsState.getBounds()),
+ getMovementBounds(adjustedNormalBounds), callback /* callback */);
}
private void animateToUnexpandedState(Rect restoreBounds) {
- Rect restoredMovementBounds = new Rect();
- mPipBoundsAlgorithm.getMovementBounds(restoreBounds,
- mInsetBounds, restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
mMotionHelper.animateToUnexpandedState(restoreBounds, mSavedSnapFraction,
- restoredMovementBounds, mPipBoundsState.getMovementBounds(), false /* immediate */);
+ getMovementBounds(restoreBounds),
+ getMovementBounds(mPipBoundsState.getBounds()), false /* immediate */);
mSavedSnapFraction = -1f;
}
@@ -919,10 +915,6 @@
&& mMenuState != MENU_STATE_FULL) {
// If using pinch to zoom, double-tap functions as resizing between max/min size
if (mPipResizeGestureHandler.isUsingPinchToZoom()) {
- final boolean toExpand = mPipBoundsState.getBounds().width()
- < mPipBoundsState.getMaxSize().x
- && mPipBoundsState.getBounds().height()
- < mPipBoundsState.getMaxSize().y;
if (mMenuController.isMenuVisible()) {
mMenuController.hideMenu(ANIM_TYPE_NONE, false /* resize */);
}
@@ -934,7 +926,7 @@
// actually toggle to the size chosen
if (nextSize == PipDoubleTapHelper.SIZE_SPEC_MAX) {
mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
- animateToMaximizedState(null);
+ animateToMaximizedState();
} else if (nextSize == PipDoubleTapHelper.SIZE_SPEC_DEFAULT) {
mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
animateToNormalSize(null);
@@ -1045,7 +1037,9 @@
private Rect getMovementBounds(Rect curBounds) {
Rect movementBounds = new Rect();
- mPipBoundsAlgorithm.getMovementBounds(curBounds, mInsetBounds,
+ Rect insetBounds = new Rect();
+ mPipBoundsAlgorithm.getInsetBounds(insetBounds);
+ mPipBoundsAlgorithm.getMovementBounds(curBounds, insetBounds,
movementBounds, mIsImeShowing ? mImeHeight : 0);
return movementBounds;
}
@@ -1091,6 +1085,7 @@
case PipTransitionState.ENTERED_PIP:
onActivityPinned();
mTouchState.setAllowInputEvents(true);
+ mTouchState.reset();
break;
case PipTransitionState.EXITED_PIP:
mTouchState.setAllowInputEvents(false);
@@ -1101,6 +1096,7 @@
break;
case PipTransitionState.CHANGED_PIP_BOUNDS:
mTouchState.setAllowInputEvents(true);
+ mTouchState.reset();
break;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchState.java
index d093f1e..bb8d4ee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchState.java
@@ -23,7 +23,7 @@
import android.view.ViewConfiguration;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 57dc5f9..683d30d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -71,6 +71,9 @@
static final String PIP_START_TX = "pip_start_tx";
static final String PIP_FINISH_TX = "pip_finish_tx";
static final String PIP_DESTINATION_BOUNDS = "pip_dest_bounds";
+ static final String ANIMATING_BOUNDS_CHANGE_DURATION =
+ "animating_bounds_change_duration";
+ static final int BOUNDS_CHANGE_JUMPCUT_DURATION = 0;
/**
* The fixed start delay in ms when fading out the content overlay from bounds animation.
@@ -87,7 +90,7 @@
private final PipTransitionState mPipTransitionState;
//
- // Transition tokens
+ // Transition caches
//
@Nullable
@@ -96,6 +99,8 @@
private IBinder mExitViaExpandTransition;
@Nullable
private IBinder mResizeTransition;
+ private int mBoundsChangeDuration = BOUNDS_CHANGE_JUMPCUT_DURATION;
+
//
// Internal state and relevant cached info
@@ -152,11 +157,12 @@
}
@Override
- public void startResizeTransition(WindowContainerTransaction wct) {
+ public void startResizeTransition(WindowContainerTransaction wct, int duration) {
if (wct == null) {
return;
}
mResizeTransition = mTransitions.startTransition(TRANSIT_RESIZE_PIP, wct, this);
+ mBoundsChangeDuration = duration;
}
@Nullable
@@ -272,6 +278,10 @@
extra.putParcelable(PIP_START_TX, startTransaction);
extra.putParcelable(PIP_FINISH_TX, finishTransaction);
extra.putParcelable(PIP_DESTINATION_BOUNDS, pipChange.getEndAbsBounds());
+ if (mBoundsChangeDuration > BOUNDS_CHANGE_JUMPCUT_DURATION) {
+ extra.putInt(ANIMATING_BOUNDS_CHANGE_DURATION, mBoundsChangeDuration);
+ mBoundsChangeDuration = BOUNDS_CHANGE_JUMPCUT_DURATION;
+ }
mFinishCallback = finishCallback;
mPipTransitionState.setState(PipTransitionState.CHANGING_PIP_BOUNDS, extra);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
index 9d599ca..29272be 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
@@ -29,6 +29,7 @@
import com.android.internal.util.Preconditions;
import com.android.wm.shell.shared.annotations.ShellMainThread;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -62,6 +63,8 @@
* and throw an <code>IllegalStateException</code> otherwise.</p>
*/
public class PipTransitionState {
+ private static final String TAG = PipTransitionState.class.getSimpleName();
+
public static final int UNDEFINED = 0;
// State for Launcher animating the swipe PiP to home animation.
@@ -190,8 +193,9 @@
"No extra bundle for " + stateToString(state) + " state.");
}
if (mState != state) {
- dispatchPipTransitionStateChanged(mState, state, extra);
+ final int prevState = mState;
mState = state;
+ dispatchPipTransitionStateChanged(prevState, mState, extra);
}
}
@@ -319,4 +323,11 @@
return String.format("PipTransitionState(mState=%s, mInSwipePipToHomeTransition=%b)",
stateToString(mState), mInSwipePipToHomeTransition);
}
+
+ /** Dumps internal state. */
+ public void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ pw.println(innerPrefix + "mState=" + stateToString(mState));
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index ad298dc..814eaae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -43,7 +43,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index c67cf1d..e46625d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -63,7 +63,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
index 64e26db..1cbb8bb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java
@@ -23,7 +23,7 @@
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index f5fbae5..27fd309 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -24,7 +24,7 @@
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.SyncTransactionQueue;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index dd219d3..b4941a5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -73,7 +73,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 0541a02..b3dab85 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -46,7 +46,7 @@
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 45eff4a..d9e9776 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -119,7 +119,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.R;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 0f3d6ca..1076eca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -45,7 +45,7 @@
import androidx.annotation.NonNull;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.ShellTaskOrganizer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuController.java
index 1d8a8d5..e0f6394 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuController.java
@@ -36,7 +36,7 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.split.SplitScreenConstants;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 2b12a22..90eb22f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -74,7 +74,7 @@
import com.android.internal.graphics.palette.Quantizer;
import com.android.internal.graphics.palette.VariationalKMeansQuantizer;
import com.android.internal.policy.PhoneWindow;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.TransactionPool;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java
index e552e6c..08211ab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenWindowCreator.java
@@ -53,7 +53,7 @@
import android.window.StartingWindowInfo;
import android.window.StartingWindowRemovalInfo;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ContrastColorUtil;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 3353c7b..97a695f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -43,7 +43,7 @@
import android.window.TaskSnapshot;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 8fc54ed..6e084d6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -48,7 +48,7 @@
import android.window.StartingWindowInfo;
import android.window.TaskSnapshot;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.view.BaseIWindow;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
index 72fc8686..2036d9c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/phone/PhoneStartingWindowTypeAlgorithm.java
@@ -35,7 +35,7 @@
import android.window.StartingWindowInfo;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java
index 2e6ddc3..aa9f15c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellCommandHandler.java
@@ -18,7 +18,7 @@
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_INIT;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
import java.util.Arrays;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
index 5ced1fb..0202b6c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
@@ -40,7 +40,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
import com.android.wm.shell.common.ExternalInterfaceBinder;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java
index 2e2f569..3a68009 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInit.java
@@ -25,7 +25,7 @@
import androidx.annotation.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import java.util.ArrayList;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 8ee1efa..4f4b809 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -39,7 +39,7 @@
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.activityembedding.ActivityEmbeddingController;
import com.android.wm.shell.common.split.SplitScreenUtils;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java
index c33fb80..c8921d2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedTransition.java
@@ -28,7 +28,7 @@
import android.view.SurfaceControl;
import android.window.TransitionInfo;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.activityembedding.ActivityEmbeddingController;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.pip.PipTransitionController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 9db153f..73b32a2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -103,7 +103,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.common.DisplayController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java
index 89b0e25..978b8da 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/LegacyTransitions.java
@@ -28,7 +28,7 @@
import android.view.WindowManager;
import android.window.IWindowContainerTransactionCallback;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
/**
* Utilities and interfaces for transition-like usage on top of the legacy app-transition and
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
index 7a42236..8cc7f21 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
@@ -35,7 +35,7 @@
import android.view.SurfaceControl;
import android.window.TransitionInfo;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
index 69c4167..c5dc668 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
@@ -30,7 +30,7 @@
import android.window.WindowAnimationState;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
index 9fc6702..391c5fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RecentsMixedTransition.java
@@ -30,7 +30,7 @@
import android.window.TransitionInfo;
import android.window.WindowContainerTransaction;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.desktopmode.DesktopTasksController;
import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
import com.android.wm.shell.pip.PipTransitionController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index d686046..6013a1e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -39,7 +39,7 @@
import androidx.annotation.BinderThread;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.TransitionUtil;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index 2047b5a..a5f071a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -54,7 +54,7 @@
import com.android.internal.R;
import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.shared.TransitionUtil;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index f6e38da..ec6802d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -75,7 +75,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index 7c2ba45..88bfebf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -33,7 +33,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.sysui.ShellInit;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
index 564e716..ee6c81a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
@@ -18,10 +18,10 @@
import android.util.Log
import com.android.internal.protolog.common.IProtoLogGroup
-import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.ProtoLog
/**
- * Log messages using an API similar to [com.android.internal.protolog.common.ProtoLog]. Useful for
+ * Log messages using an API similar to [com.android.internal.protolog.ProtoLog]. Useful for
* logging from Kotlin classes as ProtoLog does not have support for Kotlin.
*
* All messages are logged to logcat if logging is enabled for that [IProtoLogGroup].
@@ -29,42 +29,42 @@
// TODO(b/168581922): remove once ProtoLog adds support for Kotlin
class KtProtoLog {
companion object {
- /** @see [com.android.internal.protolog.common.ProtoLog.d] */
+ /** @see [com.android.internal.protolog.ProtoLog.d] */
fun d(group: IProtoLogGroup, messageString: String, vararg args: Any) {
if (group.isLogToLogcat) {
Log.d(group.tag, String.format(messageString, *args))
}
}
- /** @see [com.android.internal.protolog.common.ProtoLog.v] */
+ /** @see [com.android.internal.protolog.ProtoLog.v] */
fun v(group: IProtoLogGroup, messageString: String, vararg args: Any) {
if (group.isLogToLogcat) {
Log.v(group.tag, String.format(messageString, *args))
}
}
- /** @see [com.android.internal.protolog.common.ProtoLog.i] */
+ /** @see [com.android.internal.protolog.ProtoLog.i] */
fun i(group: IProtoLogGroup, messageString: String, vararg args: Any) {
if (group.isLogToLogcat) {
Log.i(group.tag, String.format(messageString, *args))
}
}
- /** @see [com.android.internal.protolog.common.ProtoLog.w] */
+ /** @see [com.android.internal.protolog.ProtoLog.w] */
fun w(group: IProtoLogGroup, messageString: String, vararg args: Any) {
if (group.isLogToLogcat) {
Log.w(group.tag, String.format(messageString, *args))
}
}
- /** @see [com.android.internal.protolog.common.ProtoLog.e] */
+ /** @see [com.android.internal.protolog.ProtoLog.e] */
fun e(group: IProtoLogGroup, messageString: String, vararg args: Any) {
if (group.isLogToLogcat) {
Log.e(group.tag, String.format(messageString, *args))
}
}
- /** @see [com.android.internal.protolog.common.ProtoLog.wtf] */
+ /** @see [com.android.internal.protolog.ProtoLog.wtf] */
fun wtf(group: IProtoLogGroup, messageString: String, vararg args: Any) {
if (group.isLogToLogcat) {
Log.wtf(group.tag, String.format(messageString, *args))
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS
new file mode 100644
index 0000000..482aaab
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/OWNERS
@@ -0,0 +1 @@
+per-file KtProtolog.kt = file:platform/development:/tools/winscope/OWNERS
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 180e4f9..a05dbf8 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
@@ -73,7 +73,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.Cuj;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index d902444..a3616f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -55,7 +55,7 @@
import android.view.WindowManagerGlobal;
import android.window.InputTransferToken;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayLayout;
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
index 35ed8de..7873a85 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
@@ -65,7 +65,7 @@
setup {
standardAppHelper.launchViaIntent(
wmHelper,
- YouTubeAppHelper.getYoutubeVideoIntent("HPcEAtoXXLA"),
+ YouTubeAppHelper.getYoutubeVideoIntent("3KtWfp0UopM"),
ComponentNameMatcher(YouTubeAppHelper.PACKAGE_NAME, "")
)
standardAppHelper.waitForVideoPlaying()
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt
index 879034f..5c539a5 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipToOtherOrientationTest.kt
@@ -73,7 +73,7 @@
setup {
standardAppHelper.launchViaIntent(
wmHelper,
- YouTubeAppHelper.getYoutubeVideoIntent("HPcEAtoXXLA"),
+ YouTubeAppHelper.getYoutubeVideoIntent("3KtWfp0UopM"),
ComponentNameMatcher(YouTubeAppHelper.PACKAGE_NAME, "")
)
standardAppHelper.enterFullscreen()
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
index c671fbe..b5a6d83 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
@@ -48,6 +48,8 @@
fun setup() {
tapl.setEnableRotation(true)
tapl.setExpectedRotation(rotation.value)
+ // TODO: b/349075982 - Remove once launcher rotation and checks are stable.
+ tapl.setExpectedRotationCheckEnabled(false)
SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp, rotation)
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
index 51a20ee..a2df22c 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTestCase.java
@@ -26,7 +26,7 @@
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import org.junit.After;
import org.junit.Before;
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 0e53e10..0bcbe13 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
@@ -193,7 +193,7 @@
.strictness(Strictness.LENIENT)
.spyStatic(DesktopModeStatus::class.java)
.startMocking()
- whenever(DesktopModeStatus.isEnabled()).thenReturn(true)
+ whenever(DesktopModeStatus.isDesktopModeFlagEnabled()).thenReturn(true)
doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
shellInit = spy(ShellInit(testExecutor))
@@ -264,7 +264,7 @@
@Test
fun instantiate_flagOff_doNotAddInitCallback() {
- whenever(DesktopModeStatus.isEnabled()).thenReturn(false)
+ whenever(DesktopModeStatus.isDesktopModeFlagEnabled()).thenReturn(false)
clearInvocations(shellInit)
createController()
@@ -1916,6 +1916,26 @@
}
@Test
+ fun toggleBounds_togglesToCalculatedBoundsForNonResizable() {
+ val bounds = Rect(0, 0, 200, 100)
+ val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds).apply {
+ topActivityInfo = ActivityInfo().apply {
+ screenOrientation = SCREEN_ORIENTATION_LANDSCAPE
+ configuration.windowConfiguration.appBounds = bounds
+ }
+ isResizeable = false
+ }
+
+ // Bounds should be 1000 x 500, vertically centered in the 1000 x 1000 stable bounds
+ val expectedBounds = Rect(STABLE_BOUNDS.left, 250, STABLE_BOUNDS.right, 750)
+
+ controller.toggleDesktopTaskSize(task)
+ // Assert bounds set to stable bounds
+ val wct = getLatestToggleResizeDesktopTaskWct()
+ assertThat(findBoundsChange(wct, task)).isEqualTo(expectedBounds)
+ }
+
+ @Test
fun toggleBounds_lastBoundsBeforeMaximizeSaved() {
val bounds = Rect(0, 0, 100, 100)
val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds)
@@ -1942,6 +1962,46 @@
}
@Test
+ fun toggleBounds_togglesFromStableBoundsToLastBoundsBeforeMaximize_nonResizeableEqualWidth() {
+ val boundsBeforeMaximize = Rect(0, 0, 100, 100)
+ val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize).apply {
+ isResizeable = false
+ }
+
+ // Maximize
+ controller.toggleDesktopTaskSize(task)
+ task.configuration.windowConfiguration.bounds.set(STABLE_BOUNDS.left,
+ boundsBeforeMaximize.top, STABLE_BOUNDS.right, boundsBeforeMaximize.bottom)
+
+ // Restore
+ controller.toggleDesktopTaskSize(task)
+
+ // Assert bounds set to last bounds before maximize
+ val wct = getLatestToggleResizeDesktopTaskWct()
+ assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
+ }
+
+ @Test
+ fun toggleBounds_togglesFromStableBoundsToLastBoundsBeforeMaximize_nonResizeableEqualHeight() {
+ val boundsBeforeMaximize = Rect(0, 0, 100, 100)
+ val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize).apply {
+ isResizeable = false
+ }
+
+ // Maximize
+ controller.toggleDesktopTaskSize(task)
+ task.configuration.windowConfiguration.bounds.set(boundsBeforeMaximize.left,
+ STABLE_BOUNDS.top, boundsBeforeMaximize.right, STABLE_BOUNDS.bottom)
+
+ // Restore
+ controller.toggleDesktopTaskSize(task)
+
+ // Assert bounds set to last bounds before maximize
+ val wct = getLatestToggleResizeDesktopTaskWct()
+ assertThat(findBoundsChange(wct, task)).isEqualTo(boundsBeforeMaximize)
+ }
+
+ @Test
fun toggleBounds_removesLastBoundsBeforeMaximizeAfterRestoringBounds() {
val boundsBeforeMaximize = Rect(0, 0, 100, 100)
val task = setUpFreeformTask(DEFAULT_DISPLAY, boundsBeforeMaximize)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
index 86aded7..ac5aeec 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
@@ -27,6 +27,9 @@
import android.testing.AndroidTestingRunner
import android.view.Display
import android.window.WindowContainerToken
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.window.flags.Flags
import com.android.wm.shell.R
import com.android.wm.shell.common.DisplayController
@@ -37,6 +40,7 @@
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertTrue
+import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -45,6 +49,7 @@
import org.mockito.Mockito.any
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
+import org.mockito.quality.Strictness
/**
* Tests for [DragPositioningCallbackUtility].
@@ -82,9 +87,13 @@
@Rule
val setFlagsRule = SetFlagsRule()
+ private lateinit var mockitoSession: StaticMockitoSession
+
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
+ mockitoSession = ExtendedMockito.mockitoSession().strictness(Strictness.LENIENT)
+ .spyStatic(DesktopModeStatus::class.java).startMocking()
whenever(taskToken.asBinder()).thenReturn(taskBinder)
whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
@@ -105,6 +114,11 @@
whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
}
+ @After
+ fun tearDown() {
+ mockitoSession.finishMocking()
+ }
+
@Test
fun testChangeBoundsDoesNotChangeHeightWhenLessThanMin() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
@@ -252,7 +266,7 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS)
fun taskMinWidthHeightUndefined_changeBoundsInDesktopModeLessThanMin_shouldNotChangeBounds() {
- whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true)
+ doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) }
initializeTaskInfo(taskMinWidth = -1, taskMinHeight = -1)
val startingPoint =
PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat())
@@ -275,7 +289,7 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS)
fun taskMinWidthHeightUndefined_changeBoundsInDesktopModeAllowedSize_shouldChangeBounds() {
- whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true)
+ doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) }
initializeTaskInfo(taskMinWidth = -1, taskMinHeight = -1)
val startingPoint =
PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.bottom.toFloat())
@@ -361,7 +375,7 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS)
fun testChangeBoundsInDesktopMode_windowSizeExceedsStableBounds_shouldBeLimitedToDisplaySize() {
- whenever(DesktopModeStatus.canEnterDesktopMode(mockContext)).thenReturn(true)
+ doReturn(true).`when`{ DesktopModeStatus.canEnterDesktopMode(mockContext) }
val startingPoint =
PointF(OFF_CENTER_STARTING_BOUNDS.right.toFloat(),
OFF_CENTER_STARTING_BOUNDS.bottom.toFloat())
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e134c23..124f1f0 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -7007,6 +7007,23 @@
}
/**
+ * Check whether a user can mute this stream type from a given UI element.
+ *
+ * <p>Only useful for volume controllers.
+ *
+ * @param streamType type of stream to check if it's mutable from UI
+ *
+ * @hide
+ */
+ public boolean isStreamMutableByUi(int streamType) {
+ try {
+ return getService().isStreamMutableByUi(streamType);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Only useful for volume controllers.
* @hide
*/
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index c8b9da5..08cc126 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -305,6 +305,8 @@
boolean isStreamAffectedByMute(int streamType);
+ boolean isStreamMutableByUi(int streamType);
+
void disableSafeMediaVolume(String callingPackage);
oneway void lowerVolumeToRs1(String callingPackage);
diff --git a/packages/PackageInstaller/res/layout/install_content_view.xml b/packages/PackageInstaller/res/layout/install_content_view.xml
index 524a88a..affcca1 100644
--- a/packages/PackageInstaller/res/layout/install_content_view.xml
+++ b/packages/PackageInstaller/res/layout/install_content_view.xml
@@ -34,7 +34,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@android:style/TextAppearance.Material.Subhead"
+ style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle"
android:text="@string/message_staging" />
<ProgressBar
@@ -57,7 +57,7 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@android:style/TextAppearance.Material.Subhead"
+ style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle"
android:text="@string/installing" />
<ProgressBar
@@ -74,7 +74,7 @@
android:id="@+id/install_confirm_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@android:style/TextAppearance.Material.Subhead"
+ style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle"
android:text="@string/install_confirm_question"
android:visibility="invisible"
android:scrollbars="vertical" />
@@ -83,7 +83,7 @@
android:id="@+id/install_confirm_question_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@android:style/TextAppearance.Material.Subhead"
+ style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle"
android:text="@string/install_confirm_question_update"
android:visibility="invisible"
android:scrollbars="vertical" />
@@ -92,7 +92,7 @@
android:id="@+id/install_success"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@android:style/TextAppearance.Material.Subhead"
+ style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle"
android:text="@string/install_done"
android:visibility="invisible" />
@@ -100,7 +100,7 @@
android:id="@+id/install_failed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@android:style/TextAppearance.Material.Subhead"
+ style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle"
android:text="@string/install_failed"
android:visibility="invisible" />
@@ -108,7 +108,7 @@
android:id="@+id/install_failed_blocked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@android:style/TextAppearance.Material.Subhead"
+ style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle"
android:text="@string/install_failed_blocked"
android:visibility="invisible" />
@@ -116,7 +116,7 @@
android:id="@+id/install_failed_conflict"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@android:style/TextAppearance.Material.Subhead"
+ style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle"
android:text="@string/install_failed_conflict"
android:visibility="invisible" />
@@ -124,7 +124,7 @@
android:id="@+id/install_failed_incompatible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@android:style/TextAppearance.Material.Subhead"
+ style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle"
android:text="@string/install_failed_incompatible"
android:visibility="invisible" />
@@ -132,7 +132,7 @@
android:id="@+id/install_failed_invalid_apk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@android:style/TextAppearance.Material.Subhead"
+ style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle"
android:text="@string/install_failed_invalid_apk"
android:visibility="invisible" />
diff --git a/packages/PackageInstaller/res/layout/uninstall_content_view.xml b/packages/PackageInstaller/res/layout/uninstall_content_view.xml
index 434e333..d5c5d8b 100644
--- a/packages/PackageInstaller/res/layout/uninstall_content_view.xml
+++ b/packages/PackageInstaller/res/layout/uninstall_content_view.xml
@@ -22,32 +22,32 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:theme="?android:attr/alertDialogTheme"
- android:orientation="vertical"
- android:paddingTop="8dp"
- android:paddingStart="?android:attr/dialogPreferredPadding"
- android:paddingEnd="?android:attr/dialogPreferredPadding"
- android:clipToPadding="false">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:theme="?android:attr/alertDialogTheme"
+ android:orientation="vertical"
+ android:paddingTop="8dp"
+ android:paddingStart="?android:attr/dialogPreferredPadding"
+ android:paddingEnd="?android:attr/dialogPreferredPadding"
+ android:clipToPadding="false">
- <TextView
- android:id="@+id/message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@android:style/TextAppearance.Material.Subhead" />
+ <TextView
+ android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle" />
- <CheckBox
- android:id="@+id/keepData"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:layout_marginStart="-8dp"
- android:paddingLeft="8sp"
- android:visibility="gone"
- style="@android:style/TextAppearance.Material.Subhead" />
+ <CheckBox
+ android:id="@+id/keepData"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginStart="-8dp"
+ android:paddingStart="8sp"
+ android:paddingEnd="0sp"
+ android:visibility="gone"
+ style="@android:style/TextAppearance.DeviceDefault.SearchResult.Subtitle" />
- </LinearLayout>
+ </LinearLayout>
</ScrollView>
diff --git a/packages/PackageInstaller/res/values-night/themes.xml b/packages/PackageInstaller/res/values-night/themes.xml
index a5b82b3..37588ad 100644
--- a/packages/PackageInstaller/res/values-night/themes.xml
+++ b/packages/PackageInstaller/res/values-night/themes.xml
@@ -19,7 +19,6 @@
<style name="Theme.AlertDialogActivity"
parent="@android:style/Theme.DeviceDefault.Dialog.Alert">
- <item name="alertDialogStyle">@style/AlertDialog</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowAnimationStyle">@null</item>
diff --git a/packages/PackageInstaller/res/values/themes.xml b/packages/PackageInstaller/res/values/themes.xml
index f5af510..aa48712 100644
--- a/packages/PackageInstaller/res/values/themes.xml
+++ b/packages/PackageInstaller/res/values/themes.xml
@@ -19,7 +19,6 @@
<style name="Theme.AlertDialogActivity"
parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
- <item name="alertDialogStyle">@style/AlertDialog</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowAnimationStyle">@null</item>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
index 2e9b7b4..a23df64 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
@@ -97,6 +97,7 @@
private set
private var callingUid = Process.INVALID_UID
private var originatingUid = Process.INVALID_UID
+ private var originatingUidFromSessionInfo = Process.INVALID_UID
private var callingPackage: String? = null
private var sessionStager: SessionStager? = null
private lateinit var intent: Intent
@@ -136,17 +137,25 @@
callingPackage = callerInfo.packageName
- if (sessionId != SessionInfo.INVALID_ID) {
- val sessionInfo: SessionInfo? = packageInstaller.getSessionInfo(sessionId)
- callingPackage = sessionInfo?.getInstallerPackageName()
- callingAttributionTag = sessionInfo?.getInstallerAttributionTag()
- }
-
// Uid of the source package, coming from ActivityManager
callingUid = callerInfo.uid
if (callingUid == Process.INVALID_UID) {
Log.e(LOG_TAG, "Could not determine the launching uid.")
}
+
+ originatingUidFromSessionInfo = callingUid
+ val sessionInfo: SessionInfo? =
+ if (sessionId != SessionInfo.INVALID_ID)
+ packageInstaller.getSessionInfo(sessionId)
+ else null
+ if (sessionInfo != null) {
+ callingPackage = sessionInfo.installerPackageName
+ callingAttributionTag = sessionInfo.installerAttributionTag
+ if (sessionInfo.originatingUid != Process.INVALID_UID) {
+ originatingUidFromSessionInfo = sessionInfo.originatingUid
+ }
+ }
+
val sourceInfo: ApplicationInfo? = getSourceInfo(callingPackage)
// Uid of the source package, with a preference to uid from ApplicationInfo
originatingUid = sourceInfo?.uid ?: callingUid
@@ -651,7 +660,12 @@
private fun getUpdateMessage(pkgInfo: PackageInfo, userActionReason: Int): String? {
if (isAppUpdating(pkgInfo)) {
val existingUpdateOwnerLabel = getExistingUpdateOwnerLabel(pkgInfo)
- val requestedUpdateOwnerLabel = getApplicationLabel(callingPackage)
+
+ val originatingPackageNameFromSessionInfo =
+ getPackageNameForUid(context, originatingUidFromSessionInfo, callingPackage)
+ val requestedUpdateOwnerLabel =
+ getApplicationLabel(originatingPackageNameFromSessionInfo)
+
if (!TextUtils.isEmpty(existingUpdateOwnerLabel)
&& userActionReason == PackageInstaller.REASON_REMIND_OWNERSHIP
) {
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 27c386e..cfd74d4 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1010,10 +1010,10 @@
<!-- UI debug setting: force allow on external summary [CHAR LIMIT=150] -->
<string name="force_resizable_activities_summary">Make all activities resizable for multi-window, regardless of manifest values.</string>
- <!-- UI debug setting: enable freeform window support [CHAR LIMIT=50] -->
- <string name="enable_freeform_support">Enable freeform windows</string>
- <!-- UI debug setting: enable freeform window support summary [CHAR LIMIT=150] -->
- <string name="enable_freeform_support_summary">Enable support for experimental freeform windows.</string>
+ <!-- UI debug setting: enable legacy freeform window support [CHAR LIMIT=50] -->
+ <string name="enable_freeform_support">Enable freeform windows (legacy)</string>
+ <!-- UI debug setting: enable legacy freeform window support summary [CHAR LIMIT=150] -->
+ <string name="enable_freeform_support_summary">Enable support for experimental legacy freeform windows.</string>
<!-- Local (desktop) backup password menu title [CHAR LIMIT=25] -->
<string name="local_backup_password_title">Desktop backup password</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
index 837c682..c88c4c9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
@@ -182,7 +182,7 @@
minVolume = getMinVolume(audioStream),
maxVolume = audioManager.getStreamMaxVolume(audioStream.value),
volume = audioManager.getStreamVolume(audioStream.value),
- isAffectedByMute = audioManager.isStreamAffectedByMute(audioStream.value),
+ isAffectedByMute = audioManager.isStreamMutableByUi(audioStream.value),
isAffectedByRingerMode = audioManager.isStreamAffectedByRingerMode(audioStream.value),
isMuted = audioManager.isStreamMute(audioStream.value),
)
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index d54236e..54f0d7a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1189,6 +1189,8 @@
synchronized (mLock) {
if (getSyncDisabledModeConfigLocked() != SYNC_DISABLED_MODE_NONE) {
+ Slog.v(LOG_TAG, "did not write settings for prefix '"
+ + prefix + "' because sync is disabled");
return SET_ALL_RESULT_DISABLED;
}
final int key = makeKey(SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 5f8e933..411decd 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -177,6 +177,7 @@
Settings.Global.DESK_UNDOCK_SOUND,
Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT,
Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS,
+ Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
Settings.Global.DEVELOPMENT_FORCE_RTL,
Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 1b9a09d..666d939 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -280,6 +280,9 @@
<!-- to adjust volume in volume panel -->
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+ <!-- to get bluetooth audio device category -->
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED" />
+
<!-- to access ResolverRankerServices -->
<uses-permission android:name="android.permission.BIND_RESOLVER_RANKER_SERVICE" />
@@ -373,8 +376,6 @@
<!-- Listen to (dis-)connection of external displays and enable / disable them. -->
<uses-permission android:name="android.permission.MANAGE_DISPLAYS" />
- <uses-permission android:name="android.permission.SET_BIOMETRIC_DIALOG_ADVANCED" />
-
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 0731616..f5153e1 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1122,3 +1122,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "translucent_occluding_activity_fix"
+ namespace: "systemui"
+ description: "Fixes occlusion animation for transluent activities"
+ bug: "303010980"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index b6e4e9b..c14ee62 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -22,6 +22,7 @@
import android.app.TaskInfo
import android.app.WindowConfiguration
import android.content.ComponentName
+import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Rect
import android.graphics.RectF
@@ -53,6 +54,7 @@
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.systemui.Flags.activityTransitionUseLargestWindow
+import com.android.systemui.Flags.translucentOccludingActivityFix
import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
import com.android.wm.shell.shared.IShellTransitions
import com.android.wm.shell.shared.ShellTransitions
@@ -991,7 +993,12 @@
controller.createAnimatorState()
}
val windowBackgroundColor =
- window.taskInfo?.let { callback.getBackgroundColor(it) } ?: window.backgroundColor
+ if (translucentOccludingActivityFix() && window.isTranslucent) {
+ Color.TRANSPARENT
+ } else {
+ window.taskInfo?.let { callback.getBackgroundColor(it) }
+ ?: window.backgroundColor
+ }
// TODO(b/184121838): We should somehow get the top and bottom radius of the window
// instead of recomputing isExpandingFullyAbove here.
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
index 4eae14b3..07898b0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/GridDragDropState.kt
@@ -108,7 +108,12 @@
private val draggingItemLayoutInfo: LazyGridItemInfo?
get() = state.layoutInfo.visibleItemsInfo.firstOrNull { it.index == draggingItemIndex }
- internal fun onDragStart(offset: Offset, contentOffset: Offset) {
+ /**
+ * Called when dragging is initiated.
+ *
+ * @return {@code True} if dragging a grid item, {@code False} otherwise.
+ */
+ internal fun onDragStart(offset: Offset, contentOffset: Offset): Boolean {
state.layoutInfo.visibleItemsInfo
.filter { item -> contentListState.isItemEditable(item.index) }
// grid item offset is based off grid content container so we need to deduct
@@ -118,7 +123,10 @@
dragStartPointerOffset = offset - this.offset.toOffset()
draggingItemIndex = index
draggingItemInitialOffset = this.offset.toOffset()
+ return true
}
+
+ return false
}
internal fun onDragInterrupted() {
@@ -216,8 +224,9 @@
dragDropState.onDrag(offset = offset)
},
onDragStart = { offset ->
- dragDropState.onDragStart(offset, contentOffset)
- viewModel.onReorderWidgetStart()
+ if (dragDropState.onDragStart(offset, contentOffset)) {
+ viewModel.onReorderWidgetStart()
+ }
},
onDragEnd = {
dragDropState.onDragInterrupted()
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 22566e7..9c9e6c6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -34,6 +34,8 @@
import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.UserAction
+import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.observableTransitionState
import com.android.systemui.ribbon.ui.composable.BottomRightCornerRibbon
import com.android.systemui.scene.shared.model.SceneDataSourceDelegator
@@ -56,7 +58,6 @@
* must have entries in this map.
* @param modifier A modifier.
*/
-@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun SceneContainer(
viewModel: SceneContainerViewModel,
@@ -66,8 +67,6 @@
) {
val coroutineScope = rememberCoroutineScope()
val currentSceneKey: SceneKey by viewModel.currentScene.collectAsStateWithLifecycle()
- val currentDestinations by
- viewModel.currentDestinationScenes(coroutineScope).collectAsStateWithLifecycle()
val state: MutableSceneTransitionLayoutState = remember {
MutableSceneTransitionLayoutState(
initialScene = currentSceneKey,
@@ -88,20 +87,19 @@
onDispose { viewModel.setTransitionState(null) }
}
+ val userActionsBySceneKey: Map<SceneKey, Map<UserAction, UserActionResult>> =
+ sceneByKey.values.associate { scene ->
+ val userActions by scene.destinationScenes.collectAsStateWithLifecycle(emptyMap())
+ val resolvedUserActions = viewModel.resolveSceneFamilies(userActions)
+ scene.key to resolvedUserActions
+ }
+
Box(
modifier = Modifier.fillMaxSize(),
) {
SceneTransitionLayout(state = state, modifier = modifier.fillMaxSize()) {
sceneByKey.forEach { (sceneKey, composableScene) ->
- scene(
- key = sceneKey,
- userActions =
- if (sceneKey == currentSceneKey) {
- currentDestinations
- } else {
- viewModel.resolveSceneFamilies(composableScene.destinationScenes.value)
- },
- ) {
+ scene(key = sceneKey, userActions = checkNotNull(userActionsBySceneKey[sceneKey])) {
with(composableScene) {
this@scene.Content(
modifier = Modifier.element(sceneKey.rootElementKey).fillMaxSize(),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index fa79ea0..54e0725 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -1284,6 +1284,41 @@
}
@Test
+ public void onAodDownAndDownTouchReceived() throws RemoteException {
+ final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
+ 0L);
+ final TouchProcessorResult processorResultDown =
+ new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
+ -1 /* pointerId */, touchData);
+
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+
+ // WHEN fingerprint is requested because of AOD interrupt
+ // GIVEN there's been an AoD interrupt
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
+ mScreenObserver.onScreenTurnedOn();
+ mUdfpsController.onAodInterrupt(0, 0, 0, 0);
+ mFgExecutor.runAllReady();
+
+ // and an ACTION_DOWN is received and touch is within sensor
+ when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+ processorResultDown);
+ MotionEvent firstDownEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, firstDownEvent);
+ mBiometricExecutor.runAllReady();
+ firstDownEvent.recycle();
+
+ // THEN the touch is only processed once
+ verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(),
+ anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
+ anyBoolean());
+ }
+
+ @Test
public void onTouch_pilferPointerWhenAltBouncerShowing()
throws RemoteException {
final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
index fe683e07..dcc9c7a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalDreamStartableTest.kt
@@ -47,6 +47,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnableFlags(Flags.FLAG_COMMUNAL_HUB)
@RunWith(AndroidJUnit4::class)
class CommunalDreamStartableTest : SysuiTestCase() {
private val kosmos = testKosmos()
@@ -76,7 +77,7 @@
testScope.runTest {
keyguardRepository.setDreaming(false)
powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
- whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(true)
+ whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
runCurrent()
verify(dreamManager, never()).startDream()
@@ -92,7 +93,7 @@
testScope.runTest {
keyguardRepository.setDreaming(false)
powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
- whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(true)
+ whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
runCurrent()
verify(dreamManager, never()).startDream()
@@ -118,7 +119,7 @@
keyguardRepository.setDreaming(false)
powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
// Not eligible to dream
- whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(false)
+ whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(false)
transition(from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB)
verify(dreamManager, never()).startDream()
@@ -129,7 +130,7 @@
testScope.runTest {
keyguardRepository.setDreaming(true)
powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
- whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(true)
+ whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
transition(from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB)
verify(dreamManager, never()).startDream()
@@ -140,7 +141,7 @@
testScope.runTest {
keyguardRepository.setDreaming(true)
powerRepository.setScreenPowerState(ScreenPowerState.SCREEN_ON)
- whenever(dreamManager.canStartDreaming(/* isScreenOn = */ true)).thenReturn(true)
+ whenever(dreamManager.canStartDreaming(/* isScreenOn= */ true)).thenReturn(true)
// Verify we do not trigger dreaming for any other state besides glanceable hub
for (state in KeyguardState.entries) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index fbe2c2e..cf14547 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -451,24 +451,6 @@
}
}
- @Test
- fun transitionFromDozingToGlanceableHub_forcesCommunal() =
- with(kosmos) {
- testScope.runTest {
- val scene by collectLastValue(communalSceneInteractor.currentScene)
- communalSceneInteractor.changeScene(CommunalScenes.Blank)
- assertThat(scene).isEqualTo(CommunalScenes.Blank)
-
- fakeKeyguardTransitionRepository.sendTransitionSteps(
- from = KeyguardState.DOZING,
- to = KeyguardState.GLANCEABLE_HUB,
- testScope = this
- )
-
- assertThat(scene).isEqualTo(CommunalScenes.Communal)
- }
- }
-
private fun TestScope.updateDocked(docked: Boolean) =
with(kosmos) {
runCurrent()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
index 0792a50..612f2e7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorTest.kt
@@ -34,14 +34,12 @@
import android.os.PowerManager
import android.platform.test.annotations.EnableFlags
-import android.service.dream.dreamManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
-import com.android.systemui.communal.domain.interactor.setCommunalAvailable
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -66,10 +64,8 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.reset
import org.mockito.Mockito.spy
-import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -124,66 +120,6 @@
@Test
@EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
- fun testTransitionToLockscreen_onWakeup_canDream_glanceableHubAvailable() =
- testScope.runTest {
- whenever(kosmos.dreamManager.canStartDreaming(anyBoolean())).thenReturn(true)
- kosmos.setCommunalAvailable(true)
- runCurrent()
-
- powerInteractor.setAwakeForTest()
- runCurrent()
-
- // If dreaming is possible and communal is available, then we should transition to
- // GLANCEABLE_HUB when waking up.
- assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.GLANCEABLE_HUB,
- )
- }
-
- @Test
- @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
- fun testTransitionToLockscreen_onWakeup_canNotDream_glanceableHubAvailable() =
- testScope.runTest {
- whenever(kosmos.dreamManager.canStartDreaming(anyBoolean())).thenReturn(false)
- kosmos.setCommunalAvailable(true)
- runCurrent()
-
- powerInteractor.setAwakeForTest()
- runCurrent()
-
- // If dreaming is NOT possible but communal is available, then we should transition to
- // LOCKSCREEN when waking up.
- assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.LOCKSCREEN,
- )
- }
-
- @Test
- @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
- fun testTransitionToLockscreen_onWakeup_canNDream_glanceableHubNotAvailable() =
- testScope.runTest {
- whenever(kosmos.dreamManager.canStartDreaming(anyBoolean())).thenReturn(true)
- kosmos.setCommunalAvailable(false)
- runCurrent()
-
- powerInteractor.setAwakeForTest()
- runCurrent()
-
- // If dreaming is possible but communal is NOT available, then we should transition to
- // LOCKSCREEN when waking up.
- assertThat(transitionRepository)
- .startedTransition(
- from = KeyguardState.DOZING,
- to = KeyguardState.LOCKSCREEN,
- )
- }
-
- @Test
- @EnableFlags(Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR)
fun testTransitionToGlanceableHub_onWakeup_ifIdleOnCommunal_noOccludingActivity() =
testScope.runTest {
kosmos.fakeCommunalSceneRepository.setTransitionState(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
index 9ce2e0f..c33e2a4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
@@ -92,7 +92,8 @@
runCurrent()
assertThat(states()).isNotEmpty()
- assertThat(states().first().label).isEqualTo(testTileData)
+ assertThat(states().last()).isNotNull()
+ assertThat(states().last()!!.label).isEqualTo(testTileData)
verify(qsTileLogger).logInitialRequest(eq(tileConfig.tileSpec))
}
@@ -196,6 +197,7 @@
qsTileLogger,
FakeSystemClock(),
testCoroutineDispatcher,
+ testCoroutineDispatcher,
scope.backgroundScope,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
index 6066d24..7955f2f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
@@ -256,6 +256,7 @@
qsTileLogger,
FakeSystemClock(),
testCoroutineDispatcher,
+ testCoroutineDispatcher,
scope.backgroundScope,
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index cb4d96f..39b3662 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -133,7 +133,6 @@
sceneInteractor = sceneInteractor,
falsingInteractor = kosmos.falsingInteractor,
powerInteractor = kosmos.powerInteractor,
- scenes = kosmos.scenes,
)
.apply { setTransitionState(transitionState) }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
index 5c30379..ea95aab 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModelTest.kt
@@ -28,10 +28,8 @@
import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.fakeScenes
import com.android.systemui.scene.sceneContainerConfig
import com.android.systemui.scene.sceneKeys
-import com.android.systemui.scene.scenes
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.fakeSceneDataSource
import com.android.systemui.testKosmos
@@ -66,7 +64,6 @@
sceneInteractor = sceneInteractor,
falsingInteractor = kosmos.falsingInteractor,
powerInteractor = kosmos.powerInteractor,
- scenes = kosmos.scenes,
)
}
@@ -217,23 +214,4 @@
assertThat(isVisible).isFalse()
}
-
- @Test
- fun currentDestinationScenes_onlyTheCurrentSceneIsCollected() =
- testScope.runTest {
- val unused by collectLastValue(underTest.currentDestinationScenes(backgroundScope))
- val currentScene by collectLastValue(sceneInteractor.currentScene)
- kosmos.fakeScenes.forEach { scene ->
- fakeSceneDataSource.changeScene(toScene = scene.key)
- runCurrent()
- assertThat(currentScene).isEqualTo(scene.key)
-
- assertThat(scene.isDestinationScenesBeingCollected).isTrue()
- kosmos.fakeScenes
- .filter { it.key != scene.key }
- .forEach { otherScene ->
- assertThat(otherScene.isDestinationScenesBeingCollected).isFalse()
- }
- }
- }
}
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 177ba598..212dae2 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -233,6 +233,7 @@
<item type="id" name="smart_space_barrier_bottom" />
<item type="id" name="small_clock_guideline_top" />
<item type="id" name="weather_clock_date_and_icons_barrier_bottom" />
+ <item type="id" name="weather_clock_bc_smartspace_bottom" />
<item type="id" name="accessibility_actions_view" />
<!-- Privacy dialog -->
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 4b07402..56de5a3 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -38,7 +38,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.systemui.dagger.GlobalRootComponent;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dump.DumpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index ad142a8..9d3c6a4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -558,7 +558,12 @@
Log.w(TAG, "onTouch down received without a preceding up");
}
mActivePointerId = MotionEvent.INVALID_POINTER_ID;
- mOnFingerDown = false;
+
+ // It's possible on some devices to get duplicate touches from both doze and the
+ // normal touch listener. Don't reset the down in this case to avoid duplicate downs
+ if (!mIsAodInterruptActive) {
+ mOnFingerDown = false;
+ }
} else if (!DeviceEntryUdfpsRefactor.isEnabled()) {
if ((mLockscreenShadeTransitionController.getQSDragProgress() != 0f
&& !mAlternateBouncerInteractor.isVisibleState())
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index e31f1ad..88c3f9f6 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -18,7 +18,6 @@
import android.provider.Settings
import com.android.compose.animation.scene.SceneKey
-import com.android.compose.animation.scene.TransitionKey
import com.android.systemui.CoreStartable
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
@@ -92,8 +91,8 @@
keyguardTransitionInteractor.startedKeyguardTransitionStep
.mapLatest(::determineSceneAfterTransition)
.filterNotNull()
- .onEach { (nextScene, nextTransition) ->
- communalSceneInteractor.changeScene(nextScene, nextTransition)
+ .onEach { nextScene ->
+ communalSceneInteractor.changeScene(nextScene, CommunalTransitionKeys.SimpleFade)
}
.launchIn(applicationScope)
@@ -189,7 +188,7 @@
private suspend fun determineSceneAfterTransition(
lastStartedTransition: TransitionStep,
- ): Pair<SceneKey, TransitionKey>? {
+ ): SceneKey? {
val to = lastStartedTransition.to
val from = lastStartedTransition.from
val docked = dockManager.isDocked
@@ -202,27 +201,22 @@
// underneath the hub is shown. When launching activities over lockscreen, we only
// change scenes once the activity launch animation is finished, so avoid
// changing the scene here.
- Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
+ CommunalScenes.Blank
}
to == KeyguardState.GLANCEABLE_HUB && from == KeyguardState.OCCLUDED -> {
// When transitioning to the hub from an occluded state, fade out the hub without
// doing any translation.
- Pair(CommunalScenes.Communal, CommunalTransitionKeys.SimpleFade)
+ CommunalScenes.Communal
}
// Transitioning to Blank scene when entering the edit mode will be handled separately
// with custom animations.
to == KeyguardState.GONE && !communalInteractor.editModeOpen.value ->
- Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
+ CommunalScenes.Blank
!docked && !KeyguardState.deviceIsAwakeInState(to) -> {
// If the user taps the screen and wakes the device within this timeout, we don't
// want to dismiss the hub
delay(AWAKE_DEBOUNCE_DELAY)
- Pair(CommunalScenes.Blank, CommunalTransitionKeys.SimpleFade)
- }
- from == KeyguardState.DOZING && to == KeyguardState.GLANCEABLE_HUB -> {
- // Make sure the communal hub is showing (immediately, not fading in) when
- // transitioning from dozing to hub.
- Pair(CommunalScenes.Communal, CommunalTransitionKeys.Immediately)
+ CommunalScenes.Blank
}
else -> null
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 1404340..af7ecf6 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -29,6 +29,7 @@
import com.android.systemui.keyguard.MigrateClocksToBlueprint
import com.android.systemui.keyguard.shared.ComposeLockscreen
import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.statusbar.notification.collection.SortBySectionTimeFlag
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor
@@ -62,6 +63,9 @@
// CommunalHub dependencies
communalHub dependsOn MigrateClocksToBlueprint.token
+
+ // DualShade dependencies
+ DualShade.token dependsOn SceneContainerFlag.getMainAconfigFlag()
}
private inline val politeNotifications
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index c1de381..1e4fb4f 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -51,14 +51,10 @@
import android.database.ContentObserver;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.BiometricPrompt;
-import android.hardware.biometrics.Flags;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -861,29 +857,6 @@
if (ActivityManager.isUserAMonkey()) {
return;
}
- if (Flags.mandatoryBiometrics()
- && requestBiometricAuthenticationForMandatoryBiometrics()) {
- launchBiometricPromptForMandatoryBiometrics(
- new BiometricPrompt.AuthenticationCallback() {
- @Override
- public void onAuthenticationError(int errorCode,
- CharSequence errString) {
- super.onAuthenticationError(errorCode, errString);
- }
-
- @Override
- public void onAuthenticationSucceeded(
- BiometricPrompt.AuthenticationResult result) {
- super.onAuthenticationSucceeded(result);
- shutDown();
- }
- });
- } else {
- shutDown();
- }
- }
-
- private void shutDown() {
mUiEventLogger.log(GlobalActionsEvent.GA_SHUTDOWN_PRESS);
// shutdown by making sure radio and power are handled accordingly.
mWindowManagerFuncs.shutdown();
@@ -2288,35 +2261,6 @@
}
@VisibleForTesting
- void launchBiometricPromptForMandatoryBiometrics(
- BiometricPrompt.AuthenticationCallback authenticationCallback) {
- final CancellationSignal cancellationSignal = new CancellationSignal();
- final BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(mContext)
- .setAllowedAuthenticators(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)
- .setUseDefaultTitle()
- .setDescription(mContext.getString(
- R.string.identity_check_biometric_prompt_description))
- .setNegativeButton(mContext.getString(R.string.cancel), mContext.getMainExecutor(),
- (dialog, which) -> cancellationSignal.cancel())
- .setAllowBackgroundAuthentication(true)
- .build();
- biometricPrompt.authenticate(cancellationSignal, mContext.getMainExecutor(),
- authenticationCallback);
- }
-
- private boolean requestBiometricAuthenticationForMandatoryBiometrics() {
- final BiometricManager biometricManager =
- (BiometricManager) mContext.getSystemService(Context.BIOMETRIC_SERVICE);
- if (biometricManager == null) {
- Log.e(TAG, "Biometric Manager is null.");
- return false;
- }
- final int status = biometricManager.canAuthenticate(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
- return status == BiometricManager.BIOMETRIC_SUCCESS;
- }
-
- @VisibleForTesting
static class ActionsDialogLite extends SystemUIDialog implements DialogInterface,
ColorExtractor.OnColorsChangedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 73347ad..1ea5d1c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -42,6 +42,7 @@
import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.Flags.notifyPowerManagerUserActivityBackground;
import static com.android.systemui.Flags.refactorGetCurrentUser;
+import static com.android.systemui.Flags.translucentOccludingActivityFix;
import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
import android.animation.Animator;
@@ -1036,6 +1037,17 @@
(int) (fullWidth - initialWidth) /* left */,
fullWidth /* right */,
mWindowCornerRadius, mWindowCornerRadius);
+ } else if (translucentOccludingActivityFix()
+ && mOccludingRemoteAnimationTarget != null
+ && mOccludingRemoteAnimationTarget.isTranslucent) {
+ // Animating in a transparent window looks really weird. Just let it be
+ // fullscreen and the app can do an internal animation if it wants to.
+ return new TransitionAnimator.State(
+ 0,
+ fullHeight,
+ 0,
+ fullWidth,
+ 0f, 0f);
} else {
final float initialHeight = fullHeight / 2f;
final float initialWidth = fullWidth / 2f;
@@ -1399,6 +1411,11 @@
private final Lazy<DreamViewModel> mDreamViewModel;
private final Lazy<CommunalTransitionViewModel> mCommunalTransitionViewModel;
private RemoteAnimationTarget mRemoteAnimationTarget;
+
+ /**
+ * The most recent RemoteAnimationTarget provided for an occluding activity animation.
+ */
+ private RemoteAnimationTarget mOccludingRemoteAnimationTarget;
private boolean mShowCommunalWhenUnoccluding = false;
private final Lazy<WindowManagerLockscreenVisibilityManager> mWmLockscreenVisibilityManager;
@@ -3941,6 +3958,13 @@
public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
+ // Save mRemoteAnimationTarget for reference in the animation controller. Needs to be
+ // called prior to super.onAnimationStart() since that's the call that eventually asks
+ // the animation controller to configure the animation state.
+ if (apps.length > 0) {
+ mOccludingRemoteAnimationTarget = apps[0];
+ }
+
super.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback);
mInteractionJankMonitor.begin(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 506a18d..b423ed9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -17,10 +17,8 @@
package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
-import android.app.DreamManager
import com.android.app.animation.Interpolators
import com.android.systemui.communal.domain.interactor.CommunalInteractor
-import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
@@ -53,10 +51,8 @@
keyguardInteractor: KeyguardInteractor,
powerInteractor: PowerInteractor,
private val communalInteractor: CommunalInteractor,
- private val communalSceneInteractor: CommunalSceneInteractor,
keyguardOcclusionInteractor: KeyguardOcclusionInteractor,
val deviceEntryRepository: DeviceEntryRepository,
- private val dreamManager: DreamManager,
) :
TransitionInteractor(
fromState = KeyguardState.DOZING,
@@ -123,8 +119,7 @@
.filterRelevantKeyguardStateAnd { isAwake -> isAwake }
.sample(
keyguardInteractor.isKeyguardOccluded,
- communalInteractor.isCommunalAvailable,
- communalSceneInteractor.isIdleOnCommunal,
+ communalInteractor.isIdleOnCommunal,
canTransitionToGoneOnWake,
keyguardInteractor.primaryBouncerShowing,
)
@@ -132,7 +127,6 @@
(
_,
occluded,
- isCommunalAvailable,
isIdleOnCommunal,
canTransitionToGoneOnWake,
primaryBouncerShowing) ->
@@ -147,10 +141,6 @@
KeyguardState.OCCLUDED
} else if (isIdleOnCommunal) {
KeyguardState.GLANCEABLE_HUB
- } else if (isCommunalAvailable && dreamManager.canStartDreaming(true)) {
- // This case handles tapping the power button to transition through
- // dream -> off -> hub.
- KeyguardState.GLANCEABLE_HUB
} else {
KeyguardState.LOCKSCREEN
}
@@ -169,8 +159,7 @@
powerInteractor.detailedWakefulness
.filterRelevantKeyguardStateAnd { it.isAwake() }
.sample(
- communalInteractor.isCommunalAvailable,
- communalSceneInteractor.isIdleOnCommunal,
+ communalInteractor.isIdleOnCommunal,
keyguardInteractor.biometricUnlockState,
canTransitionToGoneOnWake,
keyguardInteractor.primaryBouncerShowing,
@@ -178,7 +167,6 @@
.collect {
(
_,
- isCommunalAvailable,
isIdleOnCommunal,
biometricUnlockState,
canDismissLockscreen,
@@ -200,10 +188,6 @@
KeyguardState.PRIMARY_BOUNCER
} else if (isIdleOnCommunal) {
KeyguardState.GLANCEABLE_HUB
- } else if (isCommunalAvailable && dreamManager.canStartDreaming(true)) {
- // This case handles tapping the power button to transition through
- // dream -> off -> hub.
- KeyguardState.GLANCEABLE_HUB
} else {
KeyguardState.LOCKSCREEN
},
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 4f75e6f..22ab82b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -249,7 +249,7 @@
val isKeyguardGoingAway: Flow<Boolean> = repository.isKeyguardGoingAway
/** Keyguard can be clipped at the top as the shade is dragged */
- val topClippingBounds: Flow<Int?> =
+ val topClippingBounds: Flow<Int?> by lazy {
combineTransform(
keyguardTransitionInteractor
.transitionValue(scene = Scenes.Gone, stateWithoutSceneContainer = GONE)
@@ -263,6 +263,7 @@
}
}
.distinctUntilChanged()
+ }
/** Last point that [KeyguardRootView] view was tapped */
val lastRootViewTapPosition: Flow<Point?> = repository.lastRootViewTapPosition.asStateFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
index f2821a0..e063380 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt
@@ -37,6 +37,10 @@
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.clocks.AodClockBurnInModel
import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.util.ui.value
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
object KeyguardClockViewBinder {
@@ -99,15 +103,20 @@
launch {
if (!MigrateClocksToBlueprint.isEnabled) return@launch
- viewModel.isAodIconsVisible.collect {
- viewModel.currentClock.value?.let {
- if (
- viewModel.isLargeClockVisible.value && it.config.useCustomClockScene
- ) {
- blueprintInteractor.refreshBlueprint(Type.DefaultTransition)
+ combine(
+ viewModel.hasAodIcons,
+ rootViewModel.isNotifIconContainerVisible.map { it.value }
+ ) { hasIcon, isVisible ->
+ hasIcon && isVisible
+ }
+ .distinctUntilChanged()
+ .collect { _ ->
+ viewModel.currentClock.value?.let {
+ if (it.config.useCustomClockScene) {
+ blueprintInteractor.refreshBlueprint(Type.DefaultTransition)
+ }
}
}
- }
}
launch {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
index 34a1da5..0637bba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt
@@ -45,6 +45,7 @@
import com.android.systemui.plugins.clocks.ClockFaceLayout
import com.android.systemui.res.R
import com.android.systemui.shared.R as sharedR
+import com.android.systemui.util.ui.value
import dagger.Lazy
import javax.inject.Inject
@@ -70,6 +71,7 @@
private val rootViewModel: KeyguardRootViewModel,
) : KeyguardSection() {
override fun addViews(constraintLayout: ConstraintLayout) {}
+
override fun bindData(constraintLayout: ConstraintLayout) {
if (!MigrateClocksToBlueprint.isEnabled) {
return
@@ -121,35 +123,39 @@
private fun getTargetClockFace(clock: ClockController): ClockFaceLayout =
if (keyguardClockViewModel.isLargeClockVisible.value) clock.largeClock.layout
else clock.smallClock.layout
+
private fun getNonTargetClockFace(clock: ClockController): ClockFaceLayout =
if (keyguardClockViewModel.isLargeClockVisible.value) clock.smallClock.layout
else clock.largeClock.layout
fun constrainWeatherClockDateIconsBarrier(constraints: ConstraintSet) {
constraints.apply {
- if (keyguardClockViewModel.isAodIconsVisible.value) {
+ createBarrier(
+ R.id.weather_clock_bc_smartspace_bottom,
+ Barrier.BOTTOM,
+ getDimen(ENHANCED_SMARTSPACE_HEIGHT),
+ (custR.id.weather_clock_time)
+ )
+ if (
+ rootViewModel.isNotifIconContainerVisible.value.value &&
+ keyguardClockViewModel.hasAodIcons.value
+ ) {
createBarrier(
R.id.weather_clock_date_and_icons_barrier_bottom,
Barrier.BOTTOM,
0,
- *intArrayOf(sharedR.id.bc_smartspace_view, R.id.aod_notification_icon_container)
+ *intArrayOf(
+ R.id.aod_notification_icon_container,
+ R.id.weather_clock_bc_smartspace_bottom
+ )
)
} else {
- if (smartspaceViewModel.bcSmartspaceVisibility.value == VISIBLE) {
- createBarrier(
- R.id.weather_clock_date_and_icons_barrier_bottom,
- Barrier.BOTTOM,
- 0,
- (sharedR.id.bc_smartspace_view)
- )
- } else {
- createBarrier(
- R.id.weather_clock_date_and_icons_barrier_bottom,
- Barrier.BOTTOM,
- getDimen(ENHANCED_SMARTSPACE_HEIGHT),
- (R.id.lockscreen_clock_view)
- )
- }
+ createBarrier(
+ R.id.weather_clock_date_and_icons_barrier_bottom,
+ Barrier.BOTTOM,
+ 0,
+ *intArrayOf(R.id.weather_clock_bc_smartspace_bottom)
+ )
}
}
}
@@ -198,6 +204,7 @@
companion object {
private const val DATE_WEATHER_VIEW_HEIGHT = "date_weather_view_height"
private const val ENHANCED_SMARTSPACE_HEIGHT = "enhanced_smartspace_height"
+
fun getDimen(context: Context, name: String): Int {
val res = context.packageManager.getResourcesForApplication(context.packageName)
val id = res.getIdentifier(name, "dimen", context.packageName)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModel.kt
index 4128c52..5cf100e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModel.kt
@@ -34,8 +34,8 @@
alternateBouncerInteractor: AlternateBouncerInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
) {
- val canShowAlternateBouncer: Flow<Boolean> = alternateBouncerInteractor.canShowAlternateBouncer
-
+ private val deviceSupportsAlternateBouncer: Flow<Boolean> =
+ alternateBouncerInteractor.alternateBouncerSupported
private val isTransitioningToOrFromOrShowingAlternateBouncer: Flow<Boolean> =
keyguardTransitionInteractor
.transitionValue(KeyguardState.ALTERNATE_BOUNCER)
@@ -43,8 +43,8 @@
.distinctUntilChanged()
val alternateBouncerWindowRequired: Flow<Boolean> =
- canShowAlternateBouncer.flatMapLatest { canShowAlternateBouncer ->
- if (canShowAlternateBouncer) {
+ deviceSupportsAlternateBouncer.flatMapLatest { deviceSupportsAlternateBouncer ->
+ if (deviceSupportsAlternateBouncer) {
isTransitioningToOrFromOrShowingAlternateBouncer
} else {
flowOf(false)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
index f5c521a..573b75e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModel.kt
@@ -31,7 +31,6 @@
import com.android.systemui.res.R
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.shared.model.ShadeMode
-import com.android.systemui.statusbar.notification.domain.interactor.NotificationsKeyguardInteractor
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerAlwaysOnDisplayViewModel
import com.android.systemui.statusbar.ui.SystemBarUtilsProxy
import javax.inject.Inject
@@ -50,7 +49,6 @@
keyguardClockInteractor: KeyguardClockInteractor,
@Application private val applicationScope: CoroutineScope,
aodNotificationIconViewModel: NotificationIconContainerAlwaysOnDisplayViewModel,
- notifsKeyguardInteractor: NotificationsKeyguardInteractor,
@get:VisibleForTesting val shadeInteractor: ShadeInteractor,
private val systemBarUtils: SystemBarUtilsProxy,
configurationInteractor: ConfigurationInteractor,
@@ -90,14 +88,13 @@
currentClock?.let { clock ->
val face = if (isLargeClock) clock.largeClock else clock.smallClock
face.config.hasCustomWeatherDataDisplay
- }
- ?: false
+ } ?: false
}
.stateIn(
scope = applicationScope,
started = SharingStarted.WhileSubscribed(),
- initialValue = currentClock.value?.largeClock?.config?.hasCustomWeatherDataDisplay
- ?: false
+ initialValue =
+ currentClock.value?.largeClock?.config?.hasCustomWeatherDataDisplay ?: false
)
val clockShouldBeCentered: StateFlow<Boolean> =
@@ -109,15 +106,14 @@
// To translate elements below smartspace in weather clock to avoid overlapping between date
// element in weather clock and aod icons
- val isAodIconsVisible: StateFlow<Boolean> = combine(aodNotificationIconViewModel.icons.map {
- it.visibleIcons.isNotEmpty()
- }, notifsKeyguardInteractor.areNotificationsFullyHidden) { hasIcons, visible ->
- hasIcons && visible
- }.stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = false
- )
+ val hasAodIcons: StateFlow<Boolean> =
+ aodNotificationIconViewModel.icons
+ .map { it.visibleIcons.isNotEmpty() }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = false
+ )
val currentClockLayout: StateFlow<ClockLayout> =
combine(
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index e7c2a45..bda0069 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -17,6 +17,7 @@
package com.android.systemui.media;
import android.annotation.Nullable;
+import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -123,9 +124,13 @@
boolean looping, @Nullable VolumeShaper.Configuration volumeShaperConfig)
throws RemoteException {
if (LOGD) {
- Log.d(TAG, "play(token=" + token + ", uri=" + uri + ", uid="
- + Binder.getCallingUid() + ")");
+ Log.d(TAG, "play(token=" + token + ", uri=" + uri
+ + ", uid=" + Binder.getCallingUid()
+ + ") uriUserId=" + ContentProvider.getUserIdFromUri(uri)
+ + " callingUserId=" + Binder.getCallingUserHandle().getIdentifier());
}
+ enforceUriUserId(uri);
+
Client client;
synchronized (mClients) {
client = mClients.get(token);
@@ -207,6 +212,7 @@
@Override
public String getTitle(Uri uri) {
+ enforceUriUserId(uri);
final UserHandle user = Binder.getCallingUserHandle();
return Ringtone.getTitle(getContextForUser(user), uri,
false /*followSettingsUri*/, false /*allowRemote*/);
@@ -239,6 +245,25 @@
}
throw new SecurityException("Uri is not ringtone, alarm, or notification: " + uri);
}
+
+ /**
+ * Must be called from the Binder calling thread.
+ * Ensures caller is from the same userId as the content they're trying to access.
+ * @param uri the URI to check
+ * @throws SecurityException when non-system call or userId in uri differs from the
+ * caller's userId
+ */
+ private void enforceUriUserId(Uri uri) throws SecurityException {
+ final int uriUserId = ContentProvider.getUserIdFromUri(uri);
+ final int callerUserId = Binder.getCallingUserHandle().getIdentifier();
+ // for a non-system call, verify the URI to play belongs to the same user as the caller
+ if (UserHandle.isApp(Binder.getCallingUid()) && uriUserId != callerUserId) {
+ throw new SecurityException("Illegal access to uri=" + uri
+ + " content associated with user=" + uriUserId
+ + ", request originates from user=" + callerUserId);
+ }
+ }
+
};
private Context getContextForUser(UserHandle user) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
index 4c21080..8c75cf0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.base.viewmodel
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.pipeline.shared.TileSpec
import com.android.systemui.qs.tiles.base.analytics.QSTileAnalytics
@@ -61,6 +62,7 @@
private val qsTileConfigProvider: QSTileConfigProvider,
private val systemClock: SystemClock,
@Background private val backgroundDispatcher: CoroutineDispatcher,
+ @UiBackground private val uiBackgroundDispatcher: CoroutineDispatcher,
private val customTileComponentBuilder: CustomTileComponent.Builder,
) : QSTileViewModelFactory<CustomTileDataModel> {
@@ -86,6 +88,7 @@
qsTileLogger,
systemClock,
backgroundDispatcher,
+ uiBackgroundDispatcher,
component.coroutineScope(),
)
}
@@ -106,6 +109,7 @@
private val qsTileConfigProvider: QSTileConfigProvider,
private val systemClock: SystemClock,
@Background private val backgroundDispatcher: CoroutineDispatcher,
+ @UiBackground private val uiBackgroundDispatcher: CoroutineDispatcher,
private val coroutineScopeFactory: QSTileCoroutineScopeFactory,
) : QSTileViewModelFactory<T> {
@@ -136,6 +140,7 @@
qsTileLogger,
systemClock,
backgroundDispatcher,
+ uiBackgroundDispatcher,
coroutineScopeFactory.create(),
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
index 8782524..9e84f01 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImpl.kt
@@ -40,6 +40,7 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancel
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -59,7 +60,9 @@
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
/**
* Provides a hassle-free way to implement new tiles according to current System UI architecture
@@ -81,6 +84,7 @@
private val qsTileLogger: QSTileLogger,
private val systemClock: SystemClock,
private val backgroundDispatcher: CoroutineDispatcher,
+ uiBackgroundDispatcher: CoroutineDispatcher,
private val tileScope: CoroutineScope,
) : QSTileViewModel, Dumpable {
@@ -93,18 +97,16 @@
private val tileData: SharedFlow<DATA_TYPE> = createTileDataFlow()
- override val state: SharedFlow<QSTileState> =
+ override val state: StateFlow<QSTileState?> =
tileData
.map { data ->
- mapper().map(config, data).also { state ->
- qsTileLogger.logStateUpdate(spec, state, data)
- }
+ withContext(uiBackgroundDispatcher) { mapper().map(config, data) }
+ .also { state -> qsTileLogger.logStateUpdate(spec, state, data) }
}
- .flowOn(backgroundDispatcher)
- .shareIn(
+ .stateIn(
tileScope,
SharingStarted.WhileSubscribed(),
- replay = 1,
+ null,
)
override val isAvailable: StateFlow<Boolean> =
users
@@ -147,26 +149,26 @@
private fun createTileDataFlow(): SharedFlow<DATA_TYPE> =
users
- .flatMapLatest { user ->
- val updateTriggers =
- merge(
- userInputFlow(user),
- forceUpdates
- .map { DataUpdateTrigger.ForceUpdate }
- .onEach { qsTileLogger.logForceUpdate(spec) },
- )
- .onStart {
- emit(DataUpdateTrigger.InitialRequest)
- qsTileLogger.logInitialRequest(spec)
- }
- .shareIn(tileScope, SharingStarted.WhileSubscribed())
- tileDataInteractor()
- .tileData(user, updateTriggers)
- // combine makes sure updateTriggers is always listened even if
- // tileDataInteractor#tileData doesn't flatMapLatest on it
- .combine(updateTriggers) { data, _ -> data }
- .cancellable()
- .flowOn(backgroundDispatcher)
+ .transformLatest { user ->
+ coroutineScope {
+ val updateTriggers: Flow<DataUpdateTrigger> =
+ merge(
+ userInputFlow(user),
+ forceUpdates
+ .map { DataUpdateTrigger.ForceUpdate }
+ .onEach { qsTileLogger.logForceUpdate(spec) },
+ )
+ .onStart { qsTileLogger.logInitialRequest(spec) }
+ .stateIn(this, SharingStarted.Eagerly, DataUpdateTrigger.InitialRequest)
+ tileDataInteractor()
+ .tileData(user, updateTriggers)
+ // combine makes sure updateTriggers is always listened even if
+ // tileDataInteractor#tileData doesn't transformLatest on it
+ .combine(updateTriggers) { data, _ -> data }
+ .cancellable()
+ .flowOn(backgroundDispatcher)
+ .collect { emit(it) }
+ }
}
.distinctUntilChanged()
.shareIn(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt
index 1e8ce58..233e913 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/qr/domain/interactor/QRCodeScannerTileDataInteractor.kt
@@ -30,11 +30,9 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.flow.stateIn
/** Observes one qr scanner state changes providing the [QRCodeScannerTileModel]. */
class QRCodeScannerTileDataInteractor
@@ -66,11 +64,6 @@
}
.onStart { emit(generateModel()) }
.flowOn(bgCoroutineContext)
- .stateIn(
- scope,
- SharingStarted.WhileSubscribed(),
- QRCodeScannerTileModel.TemporarilyUnavailable
- )
override fun availability(user: UserHandle): Flow<Boolean> =
flowOf(qrController.isCameraAvailable)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
index ae6c014..30247c4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileState.kt
@@ -54,18 +54,21 @@
resources: Resources,
theme: Theme,
config: QSTileUIConfig,
- build: Builder.() -> Unit
+ builder: Builder.() -> Unit
): QSTileState {
val iconDrawable = resources.getDrawable(config.iconRes, theme)
return build(
{ Icon.Loaded(iconDrawable, null) },
resources.getString(config.labelRes),
- build,
+ builder,
)
}
- fun build(icon: () -> Icon?, label: CharSequence, build: Builder.() -> Unit): QSTileState =
- Builder(icon, label).apply(build).build()
+ fun build(
+ icon: () -> Icon?,
+ label: CharSequence,
+ builder: Builder.() -> Unit
+ ): QSTileState = Builder(icon, label).apply { builder() }.build()
}
enum class ActivationState(val legacyState: Int) {
@@ -107,7 +110,9 @@
sealed interface SideViewIcon {
data class Custom(val icon: Icon) : SideViewIcon
+
data object Chevron : SideViewIcon
+
data object None : SideViewIcon
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt
index 226e2fa0..b1b0001 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModel.kt
@@ -17,7 +17,6 @@
package com.android.systemui.qs.tiles.viewmodel
import android.os.UserHandle
-import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
/**
@@ -31,7 +30,7 @@
interface QSTileViewModel {
/** State of the tile to be shown by the view. */
- val state: SharedFlow<QSTileState>
+ val state: StateFlow<QSTileState?>
val config: QSTileConfig
@@ -62,9 +61,7 @@
}
/**
- * Returns the immediate state of the tile or null if the state haven't been collected yet. Favor
- * reactive consumption over the [currentState], because there is no guarantee that current value
- * would be available at any time.
+ * Returns the immediate state of the tile or null if the state haven't been collected yet.
*/
val QSTileViewModel.currentState: QSTileState?
- get() = state.replayCache.lastOrNull()
+ get() = state.value
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
index 7be13e0..ba0a8d6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelAdapter.kt
@@ -38,6 +38,7 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collectIndexed
+import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
@@ -168,6 +169,7 @@
if (listeningClients.size == 1) {
stateJob =
qsTileViewModel.state
+ .filterNotNull()
.map { mapState(context, it, qsTileViewModel.config) }
.onEach { legacyState ->
synchronized(callbacks) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt
index 64f1fd3..00b7e61 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/viewmodel/StubQSTileViewModel.kt
@@ -17,12 +17,11 @@
package com.android.systemui.qs.tiles.viewmodel
import android.os.UserHandle
-import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
object StubQSTileViewModel : QSTileViewModel {
- override val state: SharedFlow<QSTileState>
+ override val state: StateFlow<QSTileState?>
get() = error("Don't call stubs")
override val config: QSTileConfig
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index d380251..a28222e 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -26,17 +26,12 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.Scene
import com.android.systemui.scene.shared.model.Scenes
-import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
/** Models UI state for the scene container. */
@SysUISingleton
@@ -46,7 +41,6 @@
private val sceneInteractor: SceneInteractor,
private val falsingInteractor: FalsingInteractor,
private val powerInteractor: PowerInteractor,
- scenes: Set<@JvmSuppressWildcards Scene>,
) {
/**
* Keys of all scenes in the container.
@@ -62,25 +56,6 @@
/** Whether the container is visible. */
val isVisible: StateFlow<Boolean> = sceneInteractor.isVisible
- private val destinationScenesBySceneKey =
- scenes.associate { scene ->
- scene.key to scene.destinationScenes.flatMapLatestConflated { replaceSceneFamilies(it) }
- }
-
- fun currentDestinationScenes(
- scope: CoroutineScope,
- ): StateFlow<Map<UserAction, UserActionResult>> {
- return currentScene
- .flatMapLatestConflated { currentSceneKey ->
- checkNotNull(destinationScenesBySceneKey[currentSceneKey])
- }
- .stateIn(
- scope = scope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = emptyMap(),
- )
- }
-
/**
* Binds the given flow so the system remembers it.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
index 48c89f8..5e91786 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/CommonVisualInterruptionSuppressors.kt
@@ -32,6 +32,7 @@
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.database.ContentObserver
import android.hardware.display.AmbientDisplayConfiguration
+import android.os.Bundle
import android.os.Handler
import android.os.PowerManager
import android.os.SystemProperties
@@ -368,6 +369,11 @@
PendingIntent.FLAG_IMMUTABLE
)
+ // Replace "System UI" app name with "Android System"
+ val bundle = Bundle()
+ bundle.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ context.getString(com.android.internal.R.string.android_system_label))
+
val builder =
Notification.Builder(context, NotificationChannels.ALERTS)
.setTicker(titleStr)
@@ -375,9 +381,11 @@
.setContentText(textStr)
.setSmallIcon(com.android.systemui.res.R.drawable.ic_settings)
.setCategory(Notification.CATEGORY_SYSTEM)
+ .setTimeoutAfter(/* one day in ms */ 24 * 60 * 60 * 1000L)
.setAutoCancel(true)
.addAction(android.R.drawable.button_onoff_indicator_off, actionStr, pendingIntent)
.setContentIntent(pendingIntent)
+ .addExtras(bundle)
notificationManager.notify(SystemMessage.NOTE_ADAPTIVE_NOTIFICATIONS, builder.build())
hasSeenEdu = true
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 3d8090d..aced0be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -14,6 +14,8 @@
package com.android.systemui.statusbar.phone.fragment;
+import static com.android.systemui.statusbar.phone.fragment.StatusBarVisibilityModel.createHiddenModel;
+
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.Fragment;
@@ -46,6 +48,7 @@
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.statusbar.CommandQueue;
@@ -205,6 +208,13 @@
private boolean mTransitionFromLockscreenToDreamStarted = false;
/**
+ * True if the current scene allows the home status bar (aka this status bar) to be shown, and
+ * false if the current scene should never show the home status bar. Only used if the scene
+ * container is enabled.
+ */
+ private boolean mHomeStatusBarAllowedByScene = true;
+
+ /**
* True if there's an active ongoing activity that should be showing a chip and false otherwise.
*/
private boolean mHasOngoingActivity;
@@ -522,6 +532,13 @@
mHasOngoingActivity = hasOngoingActivity;
updateStatusBarVisibilities(/* animate= */ true);
}
+
+ @Override
+ public void onIsHomeStatusBarAllowedBySceneChanged(
+ boolean isHomeStatusBarAllowedByScene) {
+ mHomeStatusBarAllowedByScene = isHomeStatusBarAllowedByScene;
+ updateStatusBarVisibilities(/* animate= */ true);
+ }
};
@Override
@@ -580,17 +597,22 @@
boolean headsUpVisible =
mStatusBarFragmentComponent.getHeadsUpAppearanceController().shouldBeVisible();
- if (!mKeyguardStateController.isLaunchTransitionFadingAway()
- && !mKeyguardStateController.isKeyguardFadingAway()
- && shouldHideStatusBar()
- && !(mStatusBarStateController.getState() == StatusBarState.KEYGUARD
- && headsUpVisible)) {
- // Hide everything
- return new StatusBarVisibilityModel(
- /* showClock= */ false,
- /* showNotificationIcons= */ false,
- /* showOngoingActivityChip= */ false,
- /* showSystemInfo= */ false);
+ if (SceneContainerFlag.isEnabled()) {
+ // With the scene container, only use the value calculated by the view model to
+ // determine if the status bar needs hiding.
+ if (!mHomeStatusBarAllowedByScene) {
+ return createHiddenModel();
+ }
+ } else {
+ // Without the scene container, use our old, mildly-hacky logic to determine if the
+ // status bar needs hiding.
+ if (!mKeyguardStateController.isLaunchTransitionFadingAway()
+ && !mKeyguardStateController.isKeyguardFadingAway()
+ && shouldHideStatusBar()
+ && !(mStatusBarStateController.getState() == StatusBarState.KEYGUARD
+ && headsUpVisible)) {
+ return createHiddenModel();
+ }
}
boolean showClock = externalModel.getShowClock() && !headsUpVisible;
@@ -698,7 +720,7 @@
}
private void hideEndSideContent(boolean animate) {
- if (!animate) {
+ if (!animate || !mAnimationsEnabled) {
mEndSideAlphaController.setAlpha(/*alpha*/ 0f, SOURCE_OTHER);
} else {
mEndSideAlphaController.animateToAlpha(/*alpha*/ 0f, SOURCE_OTHER, FADE_OUT_DURATION,
@@ -707,7 +729,7 @@
}
private void showEndSideContent(boolean animate) {
- if (!animate) {
+ if (!animate || !mAnimationsEnabled) {
mEndSideAlphaController.setAlpha(1f, SOURCE_OTHER);
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt
index fe24fae..9255e63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarVisibilityModel.kt
@@ -36,6 +36,17 @@
return createModelFromFlags(DISABLE_NONE, DISABLE2_NONE)
}
+ /** Creates a model that hides every piece of the status bar. */
+ @JvmStatic
+ fun createHiddenModel(): StatusBarVisibilityModel {
+ return StatusBarVisibilityModel(
+ showClock = false,
+ showNotificationIcons = false,
+ showOngoingActivityChip = false,
+ showSystemInfo = false,
+ )
+ }
+
/**
* Given a set of disabled flags, converts them into the correct visibility statuses.
*
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index 9449659..62bd8ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -349,6 +349,7 @@
false
}
}
+ .flowOn(bgDispatcher)
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
override val carrierId =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index de36e40..ae1898b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -30,6 +30,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.statusbar.chips.ui.binder.ChipChronometerBinder
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
@@ -136,6 +137,14 @@
}
}
}
+
+ if (SceneContainerFlag.isEnabled) {
+ launch {
+ viewModel.isHomeStatusBarAllowedByScene.collect {
+ listener.onIsHomeStatusBarAllowedBySceneChanged(it)
+ }
+ }
+ }
}
}
}
@@ -259,4 +268,10 @@
/** Called when the status of the ongoing activity chip (active or not active) has changed. */
fun onOngoingActivityStatusChanged(hasOngoingActivity: Boolean)
+
+ /**
+ * Called when the scene state has changed such that the home status bar is newly allowed or no
+ * longer allowed. See [CollapsedStatusBarViewModel.isHomeStatusBarAllowedByScene].
+ */
+ fun onIsHomeStatusBarAllowedBySceneChanged(isHomeStatusBarAllowedByScene: Boolean)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
index 95d9248..d6c3834 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
@@ -24,6 +24,9 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
@@ -65,6 +68,12 @@
val ongoingActivityChip: StateFlow<OngoingActivityChipModel>
/**
+ * True if the current scene can show the home status bar (aka this status bar), and false if
+ * the current scene should never show the home status bar.
+ */
+ val isHomeStatusBarAllowedByScene: StateFlow<Boolean>
+
+ /**
* Apps can request a low profile mode [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE] where
* status bar and navigation icons dim. In this mode, a notification dot appears where the
* notification icons would appear if they would be shown outside of this mode.
@@ -83,6 +92,8 @@
private val lightsOutInteractor: LightsOutInteractor,
private val notificationsInteractor: ActiveNotificationsInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ sceneInteractor: SceneInteractor,
+ sceneContainerOcclusionInteractor: SceneContainerOcclusionInteractor,
ongoingActivityChipsViewModel: OngoingActivityChipsViewModel,
@Application coroutineScope: CoroutineScope,
) : CollapsedStatusBarViewModel {
@@ -99,6 +110,20 @@
override val ongoingActivityChip = ongoingActivityChipsViewModel.chip
+ override val isHomeStatusBarAllowedByScene: StateFlow<Boolean> =
+ combine(
+ sceneInteractor.currentScene,
+ sceneContainerOcclusionInteractor.invisibleDueToOcclusion,
+ ) { currentScene, isOccluded ->
+ // All scenes have their own status bars, so we should only show the home status bar
+ // if we're not in a scene. The one exception: If the scene is occluded, then the
+ // occluding app needs to show the status bar. (Fullscreen apps actually won't show
+ // the status bar but that's handled with the rest of our fullscreen app logic,
+ // which lives elsewhere.)
+ currentScene == Scenes.Gone || isOccluded
+ }
+ .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), initialValue = false)
+
override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> =
if (NotificationsLiveDataStoreRefactor.isUnexpectedlyInLegacyMode()) {
emptyFlow()
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
index d10554f..b836016 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
@@ -20,13 +20,16 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Tracing
+import com.android.systemui.dagger.qualifiers.UiBackground
import dagger.Module
import dagger.Provides
+import java.util.concurrent.Executor
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.newFixedThreadPoolContext
import kotlinx.coroutines.plus
@@ -83,4 +86,25 @@
): CoroutineContext {
return bgCoroutineDispatcher + tracingCoroutineContext
}
+
+ /** Coroutine dispatcher for background operations on for UI. */
+ @Provides
+ @SysUISingleton
+ @UiBackground
+ @Deprecated(
+ "Use @UiBackground CoroutineContext instead",
+ ReplaceWith("uiBgCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+ )
+ fun uiBgDispatcher(@UiBackground uiBgExecutor: Executor): CoroutineDispatcher =
+ uiBgExecutor.asCoroutineDispatcher()
+
+ @Provides
+ @UiBackground
+ @SysUISingleton
+ fun uiBgCoroutineContext(
+ @Tracing tracingCoroutineContext: CoroutineContext,
+ @UiBackground uiBgCoroutineDispatcher: CoroutineDispatcher,
+ ): CoroutineContext {
+ return uiBgCoroutineDispatcher + tracingCoroutineContext
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index aee441a..c45f98e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -567,7 +567,7 @@
streamStateW(stream).levelMax = Math.max(1, getAudioManagerStreamMaxVolume(stream));
updateStreamMuteW(stream, mAudio.isStreamMute(stream));
final StreamState ss = streamStateW(stream);
- ss.muteSupported = mAudio.isStreamAffectedByMute(stream);
+ ss.muteSupported = mAudio.isStreamMutableByUi(stream);
ss.name = STREAMS.get(stream);
checkRoutedToBluetoothW(stream);
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index cb61534..8457bdb 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -51,7 +51,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.flags.FeatureFlags;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
index 64c162f..639b53b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ambient/touch/TouchMonitorTest.java
@@ -46,6 +46,7 @@
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleCoroutineScope;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
@@ -159,7 +160,9 @@
ArgumentCaptor<LifecycleObserver> observerCaptor =
ArgumentCaptor.forClass(LifecycleObserver.class);
verify(mLifecycleRegistry, atLeast(1)).addObserver(observerCaptor.capture());
- mLifecycleObservers.addAll(observerCaptor.getAllValues());
+ mLifecycleObservers.addAll(observerCaptor.getAllValues().stream().filter(
+ lifecycleObserver -> !(lifecycleObserver instanceof LifecycleCoroutineScope))
+ .toList());
updateLifecycle(Lifecycle.State.RESUMED);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index b58eb49..e2cca38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -23,7 +23,6 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -34,20 +33,13 @@
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.TrustManager;
-import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Color;
-import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.BiometricPrompt;
-import android.hardware.biometrics.Flags;
import android.media.AudioManager;
import android.os.Handler;
import android.os.UserManager;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.service.dreams.IDreamManager;
import android.testing.TestableLooper;
@@ -96,7 +88,6 @@
import com.android.systemui.util.settings.SecureSettings;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -111,9 +102,6 @@
@RunWith(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class GlobalActionsDialogLiteTest extends SysuiTestCase {
- @Rule
- public final CheckFlagsRule mCheckFlagsRule =
- DeviceFlagsValueProvider.createCheckFlagsRule();
private GlobalActionsDialogLite mGlobalActionsDialogLite;
@Mock private GlobalActions.GlobalActionsManager mWindowManagerFuncs;
@@ -153,7 +141,6 @@
@Mock private DialogTransitionAnimator mDialogTransitionAnimator;
@Mock private SelectedUserInteractor mSelectedUserInteractor;
@Mock private OnBackInvokedDispatcher mOnBackInvokedDispatcher;
- @Mock private BiometricManager mBiometricManager;
@Captor private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
private TestableLooper mTestableLooper;
@@ -170,13 +157,10 @@
when(mUserContextProvider.getUserContext()).thenReturn(mContext);
when(mResources.getConfiguration()).thenReturn(
getContext().getResources().getConfiguration());
- when(mBiometricManager.canAuthenticate(anyInt())).thenReturn(
- BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
mGlobalSettings = new FakeGlobalSettings();
mSecureSettings = new FakeSettings();
mInteractor = mKosmos.getGlobalActionsInteractor();
- mContext.addMockSystemService(Context.BIOMETRIC_SERVICE, mBiometricManager);
mGlobalActionsDialogLite = new GlobalActionsDialogLite(mContext,
mWindowManagerFuncs,
@@ -567,35 +551,6 @@
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS)
- public void requestBiometricAuth_whenShutDownShortPressAndMandatoryBiometricsActive() {
- mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
- ArgumentCaptor<BiometricPrompt.AuthenticationCallback>
- authenticationCallbackArgumentCaptor = ArgumentCaptor.forClass(
- BiometricPrompt.AuthenticationCallback.class);
-
- when(mBiometricManager.canAuthenticate(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS)).thenReturn(
- BiometricManager.BIOMETRIC_SUCCESS);
- doNothing().when(mGlobalActionsDialogLite).launchBiometricPromptForMandatoryBiometrics(
- any());
-
- GlobalActionsDialogLite.ShutDownAction shutDownAction =
- mGlobalActionsDialogLite.new ShutDownAction();
- shutDownAction.onPress();
-
- verify(mGlobalActionsDialogLite).launchBiometricPromptForMandatoryBiometrics(
- authenticationCallbackArgumentCaptor.capture());
-
- BiometricPrompt.AuthenticationCallback authenticationCallback =
- authenticationCallbackArgumentCaptor.getValue();
- authenticationCallback.onAuthenticationSucceeded(null);
-
- verifyLogPosted(GlobalActionsDialogLite.GlobalActionsEvent.GA_SHUTDOWN_PRESS);
- verify(mWindowManagerFuncs).shutdown();
- }
-
- @Test
public void testShouldLogLockdownPress() {
GlobalActionsDialogLite.LockDownAction lockDownAction =
mGlobalActionsDialogLite.new LockDownAction();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt
index 6398a5a..c1bd378 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerWindowViewModelTest.kt
@@ -19,26 +19,22 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.keyguard.keyguardUpdateMonitor
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository
-import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
-import com.android.systemui.statusbar.policy.keyguardStateController
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.kotlin.whenever
+import org.junit.runners.JUnit4
@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
@@ -54,35 +50,13 @@
fun alternateBouncerTransition_alternateBouncerWindowRequiredTrue() =
testScope.runTest {
mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
- val canShowAlternateBouncer by collectLastValue(underTest.canShowAlternateBouncer)
val alternateBouncerWindowRequired by
collectLastValue(underTest.alternateBouncerWindowRequired)
- givenCanShowAlternateBouncer()
fingerprintPropertyRepository.supportsUdfps()
transitionRepository.sendTransitionSteps(
listOf(
- stepToLockscreen(0f, TransitionState.STARTED),
- stepToLockscreen(.4f),
- stepToLockscreen(1f, TransitionState.FINISHED),
- ),
- testScope,
- )
- assertThat(canShowAlternateBouncer).isTrue()
- transitionRepository.sendTransitionSteps(
- listOf(
- stepFromLockscreenToAlternateBouncer(0f, TransitionState.STARTED),
- stepFromLockscreenToAlternateBouncer(.4f),
- stepFromLockscreenToAlternateBouncer(.6f),
- ),
- testScope,
- )
- assertThat(canShowAlternateBouncer).isTrue()
- assertThat(alternateBouncerWindowRequired).isTrue()
-
- transitionRepository.sendTransitionSteps(
- listOf(
stepFromAlternateBouncer(0f, TransitionState.STARTED),
- stepFromAlternateBouncer(.2f),
+ stepFromAlternateBouncer(.4f),
stepFromAlternateBouncer(.6f),
),
testScope,
@@ -104,21 +78,13 @@
mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
val alternateBouncerWindowRequired by
collectLastValue(underTest.alternateBouncerWindowRequired)
- givenCanShowAlternateBouncer()
fingerprintPropertyRepository.supportsUdfps()
transitionRepository.sendTransitionSteps(
listOf(
- stepToLockscreen(0f, TransitionState.STARTED),
- stepToLockscreen(.4f),
- stepToLockscreen(1f, TransitionState.FINISHED),
- ),
- testScope,
- )
- transitionRepository.sendTransitionSteps(
- listOf(
- stepFromLockscreenToAlternateBouncer(0f, TransitionState.STARTED),
- stepFromLockscreenToAlternateBouncer(.4f),
- stepFromLockscreenToAlternateBouncer(.6f),
+ stepFromAlternateBouncer(0f, TransitionState.STARTED),
+ stepFromAlternateBouncer(.4f),
+ stepFromAlternateBouncer(.6f),
+ stepFromAlternateBouncer(1f),
),
testScope,
)
@@ -131,23 +97,13 @@
mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
val alternateBouncerWindowRequired by
collectLastValue(underTest.alternateBouncerWindowRequired)
- givenCanShowAlternateBouncer()
fingerprintPropertyRepository.supportsUdfps()
transitionRepository.sendTransitionSteps(
listOf(
- stepFromLockscreenToDozing(0f, TransitionState.STARTED),
- stepFromLockscreenToDozing(.4f),
- stepFromLockscreenToDozing(.6f),
- stepFromLockscreenToDozing(1f, TransitionState.FINISHED),
- ),
- testScope,
- )
- assertThat(alternateBouncerWindowRequired).isFalse()
- transitionRepository.sendTransitionSteps(
- listOf(
stepFromDozingToLockscreen(0f, TransitionState.STARTED),
stepFromDozingToLockscreen(.4f),
stepFromDozingToLockscreen(.6f),
+ stepFromDozingToLockscreen(1f),
),
testScope,
)
@@ -160,39 +116,19 @@
mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
val alternateBouncerWindowRequired by
collectLastValue(underTest.alternateBouncerWindowRequired)
- givenCanShowAlternateBouncer()
fingerprintPropertyRepository.supportsRearFps()
transitionRepository.sendTransitionSteps(
listOf(
- stepToLockscreen(0f, TransitionState.STARTED),
- stepToLockscreen(.4f),
- stepToLockscreen(1f, TransitionState.FINISHED),
- ),
- testScope,
- )
- transitionRepository.sendTransitionSteps(
- listOf(
- stepFromLockscreenToAlternateBouncer(0f, TransitionState.STARTED),
- stepFromLockscreenToAlternateBouncer(.4f),
- stepFromLockscreenToAlternateBouncer(.6f),
+ stepFromAlternateBouncer(0f, TransitionState.STARTED),
+ stepFromAlternateBouncer(.4f),
+ stepFromAlternateBouncer(.6f),
+ stepFromAlternateBouncer(1f),
),
testScope,
)
assertThat(alternateBouncerWindowRequired).isFalse()
}
- private fun stepToLockscreen(
- value: Float,
- state: TransitionState = TransitionState.RUNNING
- ): TransitionStep {
- return step(
- from = KeyguardState.GONE,
- to = KeyguardState.LOCKSCREEN,
- value = value,
- transitionState = state,
- )
- }
-
private fun stepFromAlternateBouncer(
value: Float,
state: TransitionState = TransitionState.RUNNING
@@ -205,18 +141,6 @@
)
}
- private fun stepFromLockscreenToAlternateBouncer(
- value: Float,
- state: TransitionState = TransitionState.RUNNING
- ): TransitionStep {
- return step(
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.ALTERNATE_BOUNCER,
- value = value,
- transitionState = state,
- )
- }
-
private fun stepFromDozingToLockscreen(
value: Float,
state: TransitionState = TransitionState.RUNNING
@@ -229,18 +153,6 @@
)
}
- private fun stepFromLockscreenToDozing(
- value: Float,
- state: TransitionState = TransitionState.RUNNING
- ): TransitionStep {
- return step(
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.DOZING,
- value = value,
- transitionState = state,
- )
- }
-
private fun step(
from: KeyguardState,
to: KeyguardState,
@@ -255,16 +167,4 @@
ownerName = "AlternateBouncerViewModelTest"
)
}
-
- /**
- * Given the alternate bouncer parameters are set so that the alternate bouncer can show, aside
- * from the fingerprint modality.
- */
- private fun givenCanShowAlternateBouncer() {
- kosmos.fakeKeyguardBouncerRepository.setPrimaryShow(false)
- kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
- kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true)
- whenever(kosmos.keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false)
- whenever(kosmos.keyguardStateController.isUnlocked).thenReturn(false)
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt
index 42b81de..c918ed8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelImplTest.kt
@@ -97,6 +97,7 @@
qsTileLogger,
FakeSystemClock(),
testCoroutineDispatcher,
+ testCoroutineDispatcher,
testScope.backgroundScope,
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index ee27cea..01540e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -49,6 +49,8 @@
import com.android.systemui.animation.AnimatorTestRule;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.DisableSceneContainer;
+import com.android.systemui.flags.EnableSceneContainer;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.log.LogcatEchoTracker;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -302,6 +304,7 @@
}
@Test
+ @DisableSceneContainer
public void disable_shadeOpenAndShouldHide_everythingHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -318,6 +321,7 @@
}
@Test
+ @DisableSceneContainer
public void disable_shadeOpenButNotShouldHide_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -335,6 +339,7 @@
/** Regression test for b/279790651. */
@Test
+ @DisableSceneContainer
public void disable_shadeOpenAndShouldHide_thenShadeNotOpenAndDozingUpdate_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -376,6 +381,7 @@
}
@Test
+ @DisableSceneContainer
public void disable_isTransitioningToOccluded_everythingHidden() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -390,6 +396,7 @@
}
@Test
+ @DisableSceneContainer
public void disable_wasTransitioningToOccluded_transitionFinished_everythingShown() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -674,6 +681,80 @@
}
@Test
+ @EnableSceneContainer
+ public void isHomeStatusBarAllowedByScene_false_everythingHidden() {
+ resumeAndGetFragment();
+
+ mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(false);
+
+ // THEN all views are hidden
+ assertEquals(View.GONE, getClockView().getVisibility());
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
+ assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
+ }
+
+ @Test
+ @EnableSceneContainer
+ public void isHomeStatusBarAllowedByScene_true_everythingShown() {
+ resumeAndGetFragment();
+
+ mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(true);
+
+ // THEN all views are shown
+ assertEquals(View.VISIBLE, getClockView().getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ }
+
+ @Test
+ @EnableSceneContainer
+ public void disable_isHomeStatusBarAllowedBySceneFalse_disableValuesIgnored() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ // WHEN the scene doesn't allow the status bar
+ mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(false);
+
+ // BUT the disable flags want to show the status bar
+ fragment.disable(DEFAULT_DISPLAY, 0, 0, false);
+
+ // THEN all views are hidden (the disable flags aren't respected)
+ assertEquals(View.GONE, getClockView().getVisibility());
+ assertEquals(View.INVISIBLE, getNotificationAreaView().getVisibility());
+ assertEquals(View.INVISIBLE, getEndSideContentView().getVisibility());
+ }
+
+ @Test
+ @EnableSceneContainer
+ public void disable_isHomeStatusBarAllowedBySceneTrue_disableValuesUsed() {
+ CollapsedStatusBarFragment fragment = resumeAndGetFragment();
+
+ // WHEN the scene does allow the status bar
+ mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(true);
+
+ // AND the disable flags want to hide the clock
+ fragment.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_CLOCK, 0, false);
+
+ // THEN all views are shown except the clock (the disable flags are used)
+ assertEquals(View.GONE, getClockView().getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ }
+
+ @Test
+ @DisableSceneContainer
+ public void isHomeStatusBarAllowedByScene_sceneContainerDisabled_valueNotUsed() {
+ resumeAndGetFragment();
+
+ // Even if the scene says to hide the home status bar
+ mCollapsedStatusBarViewBinder.getListener().onIsHomeStatusBarAllowedBySceneChanged(false);
+
+ // The value isn't used because the scene container flag is disabled, so all views are shown
+ assertEquals(View.VISIBLE, getClockView().getVisibility());
+ assertEquals(View.VISIBLE, getNotificationAreaView().getVisibility());
+ assertEquals(View.VISIBLE, getEndSideContentView().getVisibility());
+ }
+
+ @Test
public void disable_isDozing_clockAndSystemInfoVisible() {
CollapsedStatusBarFragment fragment = resumeAndGetFragment();
when(mStatusBarStateController.isDozing()).thenReturn(true);
@@ -758,6 +839,7 @@
}
@Test
+ @DisableSceneContainer
public void testStatusBarIcons_hiddenThroughoutCameraLaunch() {
final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
@@ -779,6 +861,7 @@
}
@Test
+ @DisableSceneContainer
public void testStatusBarIcons_hiddenThroughoutLockscreenToDreamTransition() {
final CollapsedStatusBarFragment fragment = resumeAndGetFragment();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index b4c6106..94159bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -24,6 +24,7 @@
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
@@ -36,6 +37,10 @@
import com.android.systemui.log.assertLogsWtf
import com.android.systemui.mediaprojection.data.model.MediaProjectionState
import com.android.systemui.mediaprojection.data.repository.fakeMediaProjectionRepository
+import com.android.systemui.scene.data.repository.sceneContainerRepository
+import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import com.android.systemui.screenrecord.data.repository.screenRecordRepository
import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
@@ -84,6 +89,8 @@
kosmos.lightsOutInteractor,
kosmos.activeNotificationsInteractor,
kosmos.keyguardTransitionInteractor,
+ kosmos.sceneInteractor,
+ kosmos.sceneContainerOcclusionInteractor,
kosmos.ongoingActivityChipsViewModel,
kosmos.applicationCoroutineScope,
)
@@ -426,6 +433,68 @@
assertIsShareToAppChip(latest)
}
+ @Test
+ fun isHomeStatusBarAllowedByScene_sceneLockscreen_notOccluded_false() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
+ kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(false, taskInfo = null)
+
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ fun isHomeStatusBarAllowedByScene_sceneLockscreen_occluded_true() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
+ kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, taskInfo = null)
+
+ assertThat(latest).isTrue()
+ }
+
+ @Test
+ fun isHomeStatusBarAllowedByScene_sceneBouncer_false() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Bouncer)
+
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ fun isHomeStatusBarAllowedByScene_sceneCommunal_false() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Communal)
+
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ fun isHomeStatusBarAllowedByScene_sceneShade_false() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Shade)
+
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ fun isHomeStatusBarAllowedByScene_sceneGone_true() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+
+ kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
+
+ assertThat(latest).isTrue()
+ }
+
private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) =
ActiveNotificationsStore.Builder()
.apply { notifications.forEach(::addIndividualNotif) }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
index b66eed0..d3f1125 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
@@ -31,6 +31,8 @@
override val ongoingActivityChip: MutableStateFlow<OngoingActivityChipModel> =
MutableStateFlow(OngoingActivityChipModel.Hidden)
+ override val isHomeStatusBarAllowedByScene = MutableStateFlow(false)
+
override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> = areNotificationLightsOut
fun setNotificationLightsOut(lightsOut: Boolean) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index 78d8abe..a124b34 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -43,7 +43,7 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.systemui.broadcast.FakeBroadcastDispatcher;
import com.android.systemui.flags.SceneContainerRule;
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
index 5db9d31..9dae44d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
@@ -16,7 +16,6 @@
package com.android.systemui
import android.app.ActivityManager
-import android.app.DreamManager
import android.app.admin.DevicePolicyManager
import android.app.trust.TrustManager
import android.os.UserManager
@@ -33,7 +32,6 @@
import com.android.systemui.biometrics.AuthController
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.communal.domain.interactor.CommunalInteractor
-import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.demomode.DemoModeController
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.ScreenLifecycle
@@ -95,7 +93,6 @@
@get:Provides val demoModeController: DemoModeController = mock(),
@get:Provides val deviceProvisionedController: DeviceProvisionedController = mock(),
@get:Provides val dozeParameters: DozeParameters = mock(),
- @get:Provides val dreamManager: DreamManager = mock(),
@get:Provides val dumpManager: DumpManager = mock(),
@get:Provides val headsUpManager: HeadsUpManager = mock(),
@get:Provides val guestResumeSessionReceiver: GuestResumeSessionReceiver = mock(),
@@ -133,7 +130,6 @@
@get:Provides val systemUIDialogManager: SystemUIDialogManager = mock(),
@get:Provides val deviceEntryIconTransitions: Set<DeviceEntryIconTransition> = emptySet(),
@get:Provides val communalInteractor: CommunalInteractor = mock(),
- @get:Provides val communalSceneInteractor: CommunalSceneInteractor = mock(),
@get:Provides val sceneLogger: SceneLogger = mock(),
@get:Provides val trustManager: TrustManager = mock(),
@get:Provides val primaryBouncerInteractor: PrimaryBouncerInteractor = mock(),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt
index 744b127..edf77a0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractorKosmos.kt
@@ -16,9 +16,7 @@
package com.android.systemui.keyguard.domain.interactor
-import android.service.dream.dreamManager
import com.android.systemui.communal.domain.interactor.communalInteractor
-import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.deviceentry.data.repository.deviceEntryRepository
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
@@ -37,10 +35,8 @@
mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
communalInteractor = communalInteractor,
- communalSceneInteractor = communalSceneInteractor,
powerInteractor = powerInteractor,
keyguardOcclusionInteractor = keyguardOcclusionInteractor,
deviceEntryRepository = deviceEntryRepository,
- dreamManager = dreamManager
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
index 3c62b44..b5e6f75 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardClockViewModelKosmos.kt
@@ -23,7 +23,6 @@
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.notificationIconContainerAlwaysOnDisplayViewModel
-import com.android.systemui.statusbar.notification.stack.domain.interactor.notificationsKeyguardInteractor
import com.android.systemui.statusbar.ui.systemBarUtilsProxy
val Kosmos.keyguardClockViewModel by
@@ -32,7 +31,6 @@
keyguardClockInteractor = keyguardClockInteractor,
applicationScope = applicationCoroutineScope,
aodNotificationIconViewModel = notificationIconContainerAlwaysOnDisplayViewModel,
- notifsKeyguardInteractor = notificationsKeyguardInteractor,
shadeInteractor = shadeInteractor,
systemBarUtils = systemBarUtilsProxy,
configurationInteractor = configurationInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt
index 419e781..dceb8bf 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt
@@ -33,7 +33,6 @@
import com.android.systemui.util.mockito.whenever
import javax.inject.Provider
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
var Kosmos.newFactoryTileMap by Kosmos.Fixture { emptyMap<String, Provider<QSTileViewModel>>() }
@@ -50,7 +49,7 @@
instanceIdSequenceFake.newInstanceId(),
)
object : QSTileViewModel {
- override val state: SharedFlow<QSTileState> =
+ override val state: StateFlow<QSTileState?> =
MutableStateFlow(QSTileState.build({ null }, tileSpec.spec) {})
override val config: QSTileConfig = config
override val isAvailable: StateFlow<Boolean> = MutableStateFlow(true)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt
index dcfcce7..537be4f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/qr/QRCodeScannerTileKosmos.kt
@@ -69,6 +69,7 @@
qsTileLogger,
systemClock,
testDispatcher,
+ testDispatcher,
testScope.backgroundScope,
)
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 36d97f6..32491b7 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -47,6 +47,7 @@
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
import static com.android.internal.accessibility.common.ShortcutConstants.USER_SHORTCUT_TYPES;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
@@ -3086,6 +3087,7 @@
scheduleUpdateClientsIfNeededLocked(userState, forceUpdate);
updateAccessibilityShortcutTargetsLocked(userState, HARDWARE);
updateAccessibilityShortcutTargetsLocked(userState, SOFTWARE);
+ updateAccessibilityShortcutTargetsLocked(userState, GESTURE);
updateAccessibilityShortcutTargetsLocked(userState, QUICK_SETTINGS);
// Update the capabilities before the mode because we will check the current mode is
// invalid or not..
@@ -3207,6 +3209,7 @@
somethingChanged |= readAccessibilityShortcutTargetsLocked(userState, HARDWARE);
somethingChanged |= readAccessibilityShortcutTargetsLocked(userState, QUICK_SETTINGS);
somethingChanged |= readAccessibilityShortcutTargetsLocked(userState, SOFTWARE);
+ somethingChanged |= readAccessibilityShortcutTargetsLocked(userState, GESTURE);
somethingChanged |= readAccessibilityButtonTargetComponentLocked(userState);
somethingChanged |= readUserRecommendedUiTimeoutSettingsLocked(userState);
somethingChanged |= readMagnificationModeForDefaultDisplayLocked(userState);
@@ -3750,23 +3753,19 @@
return;
}
- final List<Pair<Integer, String>> shortcutTypeAndShortcutSetting = new ArrayList<>(3);
- shortcutTypeAndShortcutSetting.add(
- new Pair<>(HARDWARE,
- Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE));
- shortcutTypeAndShortcutSetting.add(
- new Pair<>(SOFTWARE,
- Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS));
+ final List<Integer> shortcutTypes = new ArrayList<>(4);
+ shortcutTypes.add(HARDWARE);
+ shortcutTypes.add(SOFTWARE);
if (android.view.accessibility.Flags.a11yQsShortcut()) {
- shortcutTypeAndShortcutSetting.add(
- new Pair<>(QUICK_SETTINGS,
- Settings.Secure.ACCESSIBILITY_QS_TARGETS));
+ shortcutTypes.add(QUICK_SETTINGS);
+ }
+ if (android.provider.Flags.a11yStandaloneGestureEnabled()) {
+ shortcutTypes.add(GESTURE);
}
final ComponentName serviceName = service.getComponentName();
- for (Pair<Integer, String> shortcutTypePair : shortcutTypeAndShortcutSetting) {
- int shortcutType = shortcutTypePair.first;
- String shortcutSettingName = shortcutTypePair.second;
+ for (Integer shortcutType: shortcutTypes) {
+ String shortcutSettingName = ShortcutUtils.convertToKey(shortcutType);
if (userState.removeShortcutTargetLocked(shortcutType, serviceName)) {
final Set<String> currentTargets = userState.getShortcutTargetsLocked(shortcutType);
persistColonDelimitedSetToSettingLocked(
@@ -4068,6 +4067,11 @@
boolean enable, @UserShortcutType int shortcutTypes,
@NonNull List<String> shortcutTargets, @UserIdInt int userId) {
enableShortcutsForTargets_enforcePermission();
+ if ((shortcutTypes & GESTURE) == GESTURE
+ && !android.provider.Flags.a11yStandaloneGestureEnabled()) {
+ throw new IllegalArgumentException(
+ "GESTURE type shortcuts are disabled by feature flag");
+ }
for (int shortcutType : USER_SHORTCUT_TYPES) {
if ((shortcutTypes & shortcutType) == shortcutType) {
enableShortcutForTargets(enable, shortcutType, shortcutTargets, userId);
@@ -5451,6 +5455,9 @@
private final Uri mAccessibilityButtonTargetsUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
+ private final Uri mAccessibilityGestureTargetsUri = Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_GESTURE_TARGETS);
+
private final Uri mUserNonInteractiveUiTimeoutUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS);
@@ -5504,6 +5511,8 @@
contentResolver.registerContentObserver(
mAccessibilityButtonTargetsUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
+ mAccessibilityGestureTargetsUri, false, this, UserHandle.USER_ALL);
+ contentResolver.registerContentObserver(
mUserNonInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
mUserInteractiveUiTimeoutUri, false, this, UserHandle.USER_ALL);
@@ -5575,6 +5584,10 @@
if (readAccessibilityShortcutTargetsLocked(userState, SOFTWARE)) {
onUserStateChangedLocked(userState);
}
+ } else if (mAccessibilityGestureTargetsUri.equals(uri)) {
+ if (readAccessibilityShortcutTargetsLocked(userState, GESTURE)) {
+ onUserStateChangedLocked(userState);
+ }
} else if (mUserNonInteractiveUiTimeoutUri.equals(uri)
|| mUserInteractiveUiTimeoutUri.equals(uri)) {
readUserRecommendedUiTimeoutSettingsLocked(userState);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 710bae9..7bcbc27 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -27,6 +27,12 @@
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TRIPLETAP;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.TWOFINGER_DOUBLETAP;
import android.accessibilityservice.AccessibilityService.SoftKeyboardShowMode;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -101,6 +107,7 @@
private final ArraySet<String> mAccessibilityShortcutKeyTargets = new ArraySet<>();
private final ArraySet<String> mAccessibilityButtonTargets = new ArraySet<>();
+ private final ArraySet<String> mAccessibilityGestureTargets = new ArraySet<>();
private final ArraySet<String> mAccessibilityQsTargets = new ArraySet<>();
/**
@@ -224,6 +231,7 @@
mTouchExplorationGrantedServices.clear();
mAccessibilityShortcutKeyTargets.clear();
mAccessibilityButtonTargets.clear();
+ mAccessibilityGestureTargets.clear();
mTargetAssignedToAccessibilityButton = null;
mIsTouchExplorationEnabled = false;
mServiceHandlesDoubleTap = false;
@@ -524,6 +532,20 @@
}
}
+ private void dumpShortcutTargets(
+ PrintWriter pw, @UserShortcutType int shortcutType, String name) {
+ pw.append(" ").append(name).append(":{");
+ ArraySet<String> targets = getShortcutTargetsInternalLocked(shortcutType);
+ int size = targets.size();
+ for (int i = 0; i < size; i++) {
+ if (i > 0) {
+ pw.append(", ");
+ }
+ pw.append(targets.valueAt(i));
+ }
+ pw.println("}");
+ }
+
void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.append("User state[");
pw.println();
@@ -553,30 +575,12 @@
.append(String.valueOf(mAlwaysOnMagnificationEnabled));
pw.append("}");
pw.println();
- pw.append(" shortcut key:{");
- int size = mAccessibilityShortcutKeyTargets.size();
- for (int i = 0; i < size; i++) {
- final String componentId = mAccessibilityShortcutKeyTargets.valueAt(i);
- pw.append(componentId);
- if (i + 1 < size) {
- pw.append(", ");
- }
- }
- pw.println("}");
- pw.append(" button:{");
- size = mAccessibilityButtonTargets.size();
- for (int i = 0; i < size; i++) {
- final String componentId = mAccessibilityButtonTargets.valueAt(i);
- pw.append(componentId);
- if (i + 1 < size) {
- pw.append(", ");
- }
- }
- pw.println("}");
+ dumpShortcutTargets(pw, HARDWARE, "shortcut key");
+ dumpShortcutTargets(pw, SOFTWARE, "button");
pw.append(" button target:{").append(mTargetAssignedToAccessibilityButton);
pw.println("}");
- pw.append(" qs shortcut targets:").append(mAccessibilityQsTargets.toString());
- pw.println();
+ dumpShortcutTargets(pw, GESTURE, "gesture");
+ dumpShortcutTargets(pw, QUICK_SETTINGS, "qs shortcut targets");
pw.append(" a11y tiles in QS panel:").append(mA11yTilesInQsPanel.toString());
pw.println();
pw.append(" Bound services:{");
@@ -782,15 +786,17 @@
}
private ArraySet<String> getShortcutTargetsInternalLocked(@UserShortcutType int shortcutType) {
- if (shortcutType == UserShortcutType.HARDWARE) {
+ if (shortcutType == HARDWARE) {
return mAccessibilityShortcutKeyTargets;
- } else if (shortcutType == UserShortcutType.SOFTWARE) {
+ } else if (shortcutType == SOFTWARE) {
return mAccessibilityButtonTargets;
- } else if (shortcutType == UserShortcutType.QUICK_SETTINGS) {
+ } else if (shortcutType == GESTURE) {
+ return mAccessibilityGestureTargets;
+ } else if (shortcutType == QUICK_SETTINGS) {
return mAccessibilityQsTargets;
- } else if ((shortcutType == UserShortcutType.TRIPLETAP
+ } else if ((shortcutType == TRIPLETAP
&& isMagnificationSingleFingerTripleTapEnabledLocked()) || (
- shortcutType == UserShortcutType.TWOFINGER_DOUBLETAP
+ shortcutType == TWOFINGER_DOUBLETAP
&& isMagnificationTwoFingerTripleTapEnabledLocked())) {
ArraySet<String> targets = new ArraySet<>();
targets.add(MAGNIFICATION_CONTROLLER_NAME);
@@ -811,7 +817,7 @@
*/
boolean updateShortcutTargetsLocked(
Set<String> newTargets, @UserShortcutType int shortcutType) {
- final int mask = UserShortcutType.TRIPLETAP | UserShortcutType.TWOFINGER_DOUBLETAP;
+ final int mask = TRIPLETAP | TWOFINGER_DOUBLETAP;
if ((shortcutType & mask) != 0) {
throw new IllegalArgumentException("Tap shortcuts cannot be updated with target sets.");
}
@@ -867,8 +873,8 @@
*/
public boolean removeShortcutTargetLocked(
@UserShortcutType int shortcutType, ComponentName target) {
- if (shortcutType == UserShortcutType.TRIPLETAP
- || shortcutType == UserShortcutType.TWOFINGER_DOUBLETAP) {
+ if (shortcutType == TRIPLETAP
+ || shortcutType == TWOFINGER_DOUBLETAP) {
throw new UnsupportedOperationException(
"removeShortcutTargetLocked only support shortcut type: "
+ "software and hardware and quick settings for now"
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 3c323f9..657e261 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -24,6 +24,7 @@
import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_ACTIVITY;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CLIPBOARD;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
@@ -720,6 +721,13 @@
}
}
break;
+ case POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR:
+ if (android.companion.virtualdevice.flags.Flags.activityControlApi()) {
+ synchronized (mVirtualDeviceLock) {
+ mDevicePolicies.put(policyType, devicePolicy);
+ }
+ }
+ break;
default:
throw new IllegalArgumentException("Device policy " + policyType
+ " cannot be changed at runtime. ");
@@ -1321,14 +1329,15 @@
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
private void onActivityBlocked(int displayId, ActivityInfo activityInfo) {
Intent intent = BlockedAppStreamingActivity.createIntent(activityInfo, getDisplayName());
- if (!android.companion.virtualdevice.flags.Flags.activityControlApi()
- || !Objects.equals(activityInfo.getComponentName(), intent.getComponent())) {
+ if (shouldShowBlockedActivityDialog(
+ activityInfo.getComponentName(), intent.getComponent())) {
mContext.startActivityAsUser(
intent.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK),
ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(),
UserHandle.SYSTEM);
}
+
if (android.companion.virtualdevice.flags.Flags.activityControlApi()) {
mActivityListenerAdapter.onActivityLaunchBlocked(
displayId,
@@ -1338,6 +1347,20 @@
}
}
+ private boolean shouldShowBlockedActivityDialog(ComponentName blockedComponent,
+ ComponentName blockedAppStreamingActivityComponent) {
+ if (!android.companion.virtualdevice.flags.Flags.activityControlApi()) {
+ return true;
+ }
+ if (Objects.equals(blockedComponent, blockedAppStreamingActivityComponent)) {
+ // Do not show the dialog if it was blocked for some reason already to avoid
+ // infinite blocking loop.
+ return false;
+ }
+ // Do not show the dialog if disabled by policy.
+ return getDevicePolicy(POLICY_TYPE_BLOCKED_ACTIVITY_BEHAVIOR) == DEVICE_POLICY_DEFAULT;
+ }
+
private void onSecureWindowShown(int displayId, int uid) {
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplays.contains(displayId)) {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index d9962c7..1cd20ed 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -47,7 +47,7 @@
],
tools: ["protologtool"],
cmd: "$(location protologtool) transform-protolog-calls " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
"--loggroups-jar $(location :protolog-groups) " +
"--viewer-config-file-path /etc/core.protolog.pb " +
@@ -66,7 +66,7 @@
],
tools: ["protologtool"],
cmd: "$(location protologtool) generate-viewer-config " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
"--loggroups-jar $(location :protolog-groups) " +
"--viewer-config-type json " +
@@ -83,7 +83,7 @@
],
tools: ["protologtool"],
cmd: "$(location protologtool) generate-viewer-config " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
"--loggroups-jar $(location :protolog-groups) " +
"--viewer-config-type proto " +
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 3d3535d..73d8384 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -197,8 +197,8 @@
/* processCpuTracker= */null, /* lastPids= */null,
CompletableFuture.completedFuture(Watchdog.getInterestingNativePids()),
/* logExceptionCreatingFile= */null, /* subject= */null,
- /* criticalEventSection= */null, Runnable::run,
- /* latencyTracker= */null);
+ /* criticalEventSection= */null, /* extraHeaders= */ null,
+ Runnable::run, /* latencyTracker= */null);
}
@Override
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 72a55dbe..21947ba 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -74,6 +74,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@@ -991,6 +992,9 @@
FrameworkStatsLog.write(FrameworkStatsLog.SYSTEM_SERVER_WATCHDOG_OCCURRED, subject);
}
+ final LinkedHashMap headersMap =
+ com.android.server.am.Flags.enableDropboxWatchdogHeaders()
+ ? new LinkedHashMap<>(Collections.singletonMap("Watchdog-Type", dropboxTag)) : null;
long anrTime = SystemClock.uptimeMillis();
StringBuilder report = new StringBuilder();
report.append(ResourcePressureUtil.currentPsiState());
@@ -998,8 +1002,9 @@
StringWriter tracesFileException = new StringWriter();
final File stack = StackTracesDumpHelper.dumpStackTraces(
pids, processCpuTracker, new SparseBooleanArray(),
- CompletableFuture.completedFuture(getInterestingNativePids()), tracesFileException,
- subject, criticalEvents, Runnable::run, /* latencyTracker= */null);
+ CompletableFuture.completedFuture(getInterestingNativePids()),
+ tracesFileException, subject, criticalEvents, headersMap,
+ Runnable::run, /* latencyTracker= */null);
// Give some extra time to make sure the stack traces get written.
// The system's been hanging for a whlie, another second or two won't hurt much.
SystemClock.sleep(5000);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f6b3b39..25fb729 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -429,7 +429,7 @@
import com.android.internal.os.Zygote;
import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.policy.AttributeCache;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index d4d4965..ba4b71c 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -60,7 +60,6 @@
import com.android.server.criticalevents.CriticalEventLog;
import com.android.server.stats.pull.ProcfsMemoryUtil.MemorySnapshot;
import com.android.server.wm.WindowProcessController;
-import com.android.server.utils.AnrTimer;
import java.io.File;
import java.io.PrintWriter;
@@ -69,6 +68,7 @@
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -429,7 +429,7 @@
}
}
// Build memory headers for the ANRing process.
- String memoryHeaders = buildMemoryHeadersFor(pid);
+ LinkedHashMap<String, String> memoryHeaders = buildMemoryHeadersFor(pid);
// Get critical event log before logging the ANR so that it doesn't occur in the log.
latencyTracker.criticalEventLogStarted();
@@ -753,7 +753,7 @@
resolver.getUserId()) != 0;
}
- private @Nullable String buildMemoryHeadersFor(int pid) {
+ private @Nullable LinkedHashMap<String, String> buildMemoryHeadersFor(int pid) {
if (pid <= 0) {
Slog.i(TAG, "Memory header requested with invalid pid: " + pid);
return null;
@@ -764,15 +764,13 @@
return null;
}
- StringBuilder memoryHeaders = new StringBuilder();
- memoryHeaders.append("RssHwmKb: ")
- .append(snapshot.rssHighWaterMarkInKilobytes)
- .append("\n");
- memoryHeaders.append("RssKb: ").append(snapshot.rssInKilobytes).append("\n");
- memoryHeaders.append("RssAnonKb: ").append(snapshot.anonRssInKilobytes).append("\n");
- memoryHeaders.append("RssShmemKb: ").append(snapshot.rssShmemKilobytes).append("\n");
- memoryHeaders.append("VmSwapKb: ").append(snapshot.swapInKilobytes).append("\n");
- return memoryHeaders.toString();
+ LinkedHashMap<String, String> memoryHeaders = new LinkedHashMap<>();
+ memoryHeaders.put("RssHwmKb", Integer.toString(snapshot.rssHighWaterMarkInKilobytes));
+ memoryHeaders.put("RssKb", Integer.toString(snapshot.rssInKilobytes));
+ memoryHeaders.put("RssAnonKb", Integer.toString(snapshot.anonRssInKilobytes));
+ memoryHeaders.put("RssShmemKb", Integer.toString(snapshot.rssShmemKilobytes));
+ memoryHeaders.put("VmSwapKb", Integer.toString(snapshot.swapInKilobytes));
+ return memoryHeaders;
}
/**
* Unless configured otherwise, swallow ANRs in background processes & kill the process.
diff --git a/services/core/java/com/android/server/am/StackTracesDumpHelper.java b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
index c1374e1..2021ba4 100644
--- a/services/core/java/com/android/server/am/StackTracesDumpHelper.java
+++ b/services/core/java/com/android/server/am/StackTracesDumpHelper.java
@@ -47,6 +47,8 @@
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -100,15 +102,17 @@
/**
* @param subject the subject of the dumped traces
* @param criticalEventSection the critical event log, passed as a string
+ * @param extraHeaders Optional, Extra headers added by the dumping method
*/
public static File dumpStackTraces(ArrayList<Integer> firstPids,
ProcessCpuTracker processCpuTracker, SparseBooleanArray lastPids,
Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile,
- String subject, String criticalEventSection, @NonNull Executor auxiliaryTaskExecutor,
+ String subject, String criticalEventSection,
+ LinkedHashMap<String, String> extraHeaders, @NonNull Executor auxiliaryTaskExecutor,
AnrLatencyTracker latencyTracker) {
return dumpStackTraces(firstPids, processCpuTracker, lastPids, nativePidsFuture,
logExceptionCreatingFile, null, subject, criticalEventSection,
- /* memoryHeaders= */ null, auxiliaryTaskExecutor, null, latencyTracker);
+ extraHeaders, auxiliaryTaskExecutor, null, latencyTracker);
}
/**
@@ -119,7 +123,7 @@
ProcessCpuTracker processCpuTracker, SparseBooleanArray lastPids,
Future<ArrayList<Integer>> nativePidsFuture, StringWriter logExceptionCreatingFile,
AtomicLong firstPidEndOffset, String subject, String criticalEventSection,
- String memoryHeaders, @NonNull Executor auxiliaryTaskExecutor,
+ LinkedHashMap<String, String> extraHeaders, @NonNull Executor auxiliaryTaskExecutor,
Future<File> firstPidFilePromise, AnrLatencyTracker latencyTracker) {
try {
@@ -159,11 +163,12 @@
}
return null;
}
+ boolean extraHeadersExist = extraHeaders != null && !extraHeaders.isEmpty();
- if (subject != null || criticalEventSection != null || memoryHeaders != null) {
+ if (subject != null || criticalEventSection != null || extraHeadersExist) {
appendtoANRFile(tracesFile.getAbsolutePath(),
(subject != null ? "Subject: " + subject + "\n" : "")
- + (memoryHeaders != null ? memoryHeaders + "\n\n" : "")
+ + (extraHeadersExist ? stringifyHeaders(extraHeaders) + "\n\n" : "")
+ (criticalEventSection != null ? criticalEventSection : ""));
}
@@ -614,4 +619,15 @@
return pids;
}
+ private static String stringifyHeaders(@NonNull LinkedHashMap<String, String> headers) {
+ StringBuilder headersString = new StringBuilder();
+ for (Map.Entry<String, String> entry : headers.entrySet()) {
+ headersString.append(entry.getKey())
+ .append(": ")
+ .append(entry.getValue())
+ .append("\n");
+ }
+ return headersString.toString();
+ }
+
}
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 0dfa330..9b380ff 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -167,4 +167,12 @@
description: "Allow logcat collection on synchronous dropbox collection"
bug: "324222683"
is_fixed_read_only: true
-}
\ No newline at end of file
+}
+
+flag {
+ name: "enable_dropbox_watchdog_headers"
+ namespace: "dropbox"
+ description: "Add watchdog-specific dropbox headers"
+ bug: "330682397"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 39cb5a9..989a4d1 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -461,6 +461,7 @@
private static final int MSG_DISPATCH_PREFERRED_MIXER_ATTRIBUTES = 52;
private static final int MSG_CONFIGURATION_CHANGED = 54;
private static final int MSG_BROADCAST_MASTER_MUTE = 55;
+ private static final int MSG_UPDATE_CONTEXTUAL_VOLUMES = 56;
/**
* Messages handled by the {@link SoundDoseHelper}, do not exceed
@@ -707,10 +708,14 @@
// Streams currently muted by ringer mode and dnd
protected static volatile int sRingerAndZenModeMutedStreams;
- /** Streams that can be muted. Do not resolve to aliases when checking.
+ /** Streams that can be muted by system. Do not resolve to aliases when checking.
* @see System#MUTE_STREAMS_AFFECTED */
private int mMuteAffectedStreams;
+ /** Streams that can be muted by user. Do not resolve to aliases when checking.
+ * @see System#MUTE_STREAMS_AFFECTED */
+ private int mUserMutableStreams;
+
@NonNull
private SoundEffectsHelper mSfxHelper;
@@ -2345,6 +2350,7 @@
mMuteAffectedStreams &= ~(1 << vss.mStreamType);
}
}
+ updateUserMutableStreams();
}
private void createStreamStates() {
@@ -2414,6 +2420,8 @@
}
pw.print("\n- mute affected streams = 0x");
pw.println(Integer.toHexString(mMuteAffectedStreams));
+ pw.print("\n- user mutable streams = 0x");
+ pw.println(Integer.toHexString(mUserMutableStreams));
}
private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
@@ -2908,6 +2916,7 @@
mMuteAffectedStreams = mSettings.getSystemIntForUser(cr,
System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
UserHandle.USER_CURRENT);
+ updateUserMutableStreams();
updateMasterMono(cr);
@@ -2927,6 +2936,12 @@
mVolumeController.loadSettings(cr);
}
+ private void updateUserMutableStreams() {
+ mUserMutableStreams = mMuteAffectedStreams;
+ mUserMutableStreams &= ~(1 << AudioSystem.STREAM_VOICE_CALL);
+ mUserMutableStreams &= ~(1 << AudioSystem.STREAM_BLUETOOTH_SCO);
+ }
+
@GuardedBy("mSettingsLock")
private void resetActiveAssistantUidsLocked() {
mActiveAssistantServiceUids = NO_ACTIVE_ASSISTANT_SERVICE_UIDS;
@@ -4466,7 +4481,7 @@
}
}
if (mVoicePlaybackActive.getAndSet(voiceActive) != voiceActive) {
- updateHearingAidVolumeOnVoiceActivityUpdate();
+ postUpdateContextualVolumes();
}
if (mMediaPlaybackActive.getAndSet(mediaActive) != mediaActive && mediaActive) {
mSoundDoseHelper.scheduleMusicActiveCheck();
@@ -4604,13 +4619,29 @@
}
}
- private void updateHearingAidVolumeOnVoiceActivityUpdate() {
- final int streamType = getBluetoothContextualVolumeStream();
- final int index = getStreamVolume(streamType);
- sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_HEARING_AID,
- mVoicePlaybackActive.get(), streamType, index));
- mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);
+ // delay between audio playback configuration update and checking
+ // actual stream activity to take async playback stop into account
+ private static final int UPDATE_CONTEXTUAL_VOLUME_DELAY_MS = 500;
+
+ /*package*/ void postUpdateContextualVolumes() {
+ sendMsg(mAudioHandler, MSG_UPDATE_CONTEXTUAL_VOLUMES, SENDMSG_REPLACE,
+ /*arg1*/ 0, /*arg2*/ 0, TAG, UPDATE_CONTEXTUAL_VOLUME_DELAY_MS);
+ }
+
+ private void onUpdateContextualVolumes() {
+ final int streamType = getBluetoothContextualVolumeStream();
+ final int device = getDeviceForStream(streamType);
+ final int index = getStreamVolume(streamType, device);
+
+ if (AudioSystem.isLeAudioDeviceType(device)) {
+ mDeviceBroker.postSetLeAudioVolumeIndex(index * 10,
+ mStreamStates[streamType].getMaxIndex(), streamType);
+ } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
+ mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);
+ }
+ sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME,
+ mVoicePlaybackActive.get(), streamType, index, device));
}
/**
@@ -7125,6 +7156,11 @@
return (mMuteAffectedStreams & (1 << streamType)) != 0;
}
+ @Override
+ public boolean isStreamMutableByUi(int streamType) {
+ return (mUserMutableStreams & (1 << streamType)) != 0;
+ }
+
private void ensureValidDirection(int direction) {
switch (direction) {
case AudioManager.ADJUST_LOWER:
@@ -9812,6 +9848,10 @@
onConfigurationChanged();
break;
+ case MSG_UPDATE_CONTEXTUAL_VOLUMES:
+ onUpdateContextualVolumes();
+ break;
+
case MusicFxHelper.MSG_EFFECT_CLIENT_GONE:
mMusicFxHelper.handleMessage(msg);
break;
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index 8ea28be..631d5d8 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -227,7 +227,7 @@
static final int VOL_SET_HEARING_AID_VOL = 3;
static final int VOL_SET_AVRCP_VOL = 4;
static final int VOL_ADJUST_VOL_UID = 5;
- static final int VOL_VOICE_ACTIVITY_HEARING_AID = 6;
+ static final int VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME = 6;
static final int VOL_MODE_CHANGE_HEARING_AID = 7;
static final int VOL_SET_GROUP_VOL = 8;
static final int VOL_MUTE_STREAM_INT = 9;
@@ -299,14 +299,14 @@
logMetricEvent();
}
- /** used for VOL_VOICE_ACTIVITY_HEARING_AID */
- VolumeEvent(int op, boolean voiceActive, int stream, int index) {
+ /** used for VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME */
+ VolumeEvent(int op, boolean voiceActive, int stream, int index, int device) {
mOp = op;
mStream = stream;
mVal1 = index;
mVal2 = voiceActive ? 1 : 0;
// unused
- mVal3 = -1;
+ mVal3 = device;
mCaller = null;
mGroupName = null;
logMetricEvent();
@@ -445,14 +445,16 @@
.set(MediaMetrics.Property.INDEX, mVal1)
.record();
return;
- case VOL_VOICE_ACTIVITY_HEARING_AID:
+ case VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME:
new MediaMetrics.Item(mMetricsId)
- .set(MediaMetrics.Property.EVENT, "voiceActivityHearingAid")
+ .set(MediaMetrics.Property.EVENT, "voiceActivityContextualVolume")
.set(MediaMetrics.Property.INDEX, mVal1)
.set(MediaMetrics.Property.STATE,
mVal2 == 1 ? "active" : "inactive")
.set(MediaMetrics.Property.STREAM_TYPE,
AudioSystem.streamToString(mStream))
+ .set(MediaMetrics.Property.DEVICE,
+ AudioSystem.getOutputDeviceName(mVal3))
.record();
return;
case VOL_MODE_CHANGE_HEARING_AID:
@@ -538,11 +540,12 @@
.append(" flags:0x").append(Integer.toHexString(mVal2))
.append(") from ").append(mCaller)
.toString();
- case VOL_VOICE_ACTIVITY_HEARING_AID:
+ case VOL_VOICE_ACTIVITY_CONTEXTUAL_VOLUME:
return new StringBuilder("Voice activity change (")
.append(mVal2 == 1 ? "active" : "inactive")
- .append(") causes setting HEARING_AID volume to idx:").append(mVal1)
+ .append(") causes setting volume to idx:").append(mVal1)
.append(" stream:").append(AudioSystem.streamToString(mStream))
+ .append(" device:").append(AudioSystem.getOutputDeviceName(mVal3))
.toString();
case VOL_MODE_CHANGE_HEARING_AID:
return new StringBuilder("setMode(")
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index f5a2a21..2a16872 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -369,10 +369,6 @@
checkPermission();
}
- if ((authenticators & Authenticators.MANDATORY_BIOMETRICS) != 0) {
- checkBiometricAdvancedPermission();
- }
-
final long identity = Binder.clearCallingIdentity();
try {
final int result = mBiometricService.canAuthenticate(
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 693a3e6..daaafcb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -418,7 +418,7 @@
}
protected int getRequestReason() {
- if (isKeyguard() && !isBiometricPrompt()) {
+ if (isKeyguard()) {
return BiometricRequestConstants.REASON_AUTH_KEYGUARD;
} else if (isBiometricPrompt()) {
// BP reason always takes precedent over settings, since callers from within
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 275c930..0f9c344 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -67,7 +67,7 @@
/**
* Represent a logical device of type TV residing in Android system.
*/
-public final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
+public class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
private static final String TAG = "HdmiCecLocalDeviceTv";
// Whether ARC is available or not. "true" means that ARC is established between TV and
@@ -113,6 +113,18 @@
// handle.
private final DelayedMessageBuffer mDelayedMessageBuffer = new DelayedMessageBuffer(this);
+ private boolean mWasActiveSourceSetToConnectedDevice = false;
+
+ @VisibleForTesting
+ protected boolean getWasActiveSourceSetToConnectedDevice() {
+ return mWasActiveSourceSetToConnectedDevice;
+ }
+
+ protected void setWasActiveSourceSetToConnectedDevice(
+ boolean wasActiveSourceSetToConnectedDevice) {
+ mWasActiveSourceSetToConnectedDevice = wasActiveSourceSetToConnectedDevice;
+ }
+
// Defines the callback invoked when TV input framework is updated with input status.
// We are interested in the notification for HDMI input addition event, in order to
// process any CEC commands that arrived before the input is added.
@@ -474,6 +486,7 @@
|| info.getDeviceType() == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
mService.getHdmiCecNetwork().updateDevicePowerStatus(logicalAddress,
HdmiControlManager.POWER_STATUS_ON);
+ setWasActiveSourceSetToConnectedDevice(true);
ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
ActiveSourceHandler.create(this, null).process(activeSource, info.getDeviceType());
} else {
@@ -489,13 +502,16 @@
protected int handleStandby(HdmiCecMessage message) {
assertRunOnServiceThread();
- // Ignore <Standby> from non-active source device.
- if (getActiveSource().logicalAddress != message.getSource()) {
+ // If a device has previously asserted the active source status, ignore <Standby> from
+ // non-active source.
+ if (getWasActiveSourceSetToConnectedDevice()
+ && getActiveSource().logicalAddress != message.getSource()) {
Slog.d(TAG, "<Standby> was not sent by the current active source, ignoring."
+ " Current active source has logical address "
+ getActiveSource().logicalAddress);
return Constants.HANDLED;
}
+ setWasActiveSourceSetToConnectedDevice(false);
return super.handleStandby(message);
}
@@ -1457,6 +1473,7 @@
invokeStandbyCompletedCallback(callback);
return;
}
+ setWasActiveSourceSetToConnectedDevice(false);
boolean sendStandbyOnSleep =
mService.getHdmiCecConfig().getIntValue(
HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP)
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
index 97c32b9..4993412 100644
--- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -255,17 +255,6 @@
}
}
- private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
- // Different languages are never compatible
- if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
- return false;
- }
- // If both the system and the keyboard layout have a country specifier, they must be equal.
- return TextUtils.isEmpty(systemLocale.getCountry())
- || TextUtils.isEmpty(keyboardLocale.getCountry())
- || systemLocale.getCountry().equals(keyboardLocale.getCountry());
- }
-
@MainThread
private void updateKeyboardLayouts() {
// Scan all input devices state for keyboard layouts that have been uninstalled.
@@ -953,21 +942,33 @@
return;
}
+ List<String> layoutNames = new ArrayList<>();
+ for (String layoutDesc : config.getConfiguredLayouts()) {
+ KeyboardLayout kl = getKeyboardLayout(layoutDesc);
+ if (kl == null) {
+ // b/349033234: Weird state with stale keyboard layout configured.
+ // Possibly due to race condition between KCM providing package being removed and
+ // corresponding layouts being removed from Datastore and cache.
+ // {@see updateKeyboardLayouts()}
+ //
+ // Ideally notification will be correctly shown after the keyboard layouts are
+ // configured again with the new package state.
+ return;
+ }
+ layoutNames.add(kl.getLabel());
+ }
showKeyboardLayoutNotification(
r.getString(
R.string.keyboard_layout_notification_selected_title,
inputDevice.getName()),
- createConfiguredNotificationText(mContext, config.getConfiguredLayouts()),
+ createConfiguredNotificationText(mContext, layoutNames),
inputDevice);
}
@MainThread
private String createConfiguredNotificationText(@NonNull Context context,
- @NonNull Set<String> selectedLayouts) {
+ @NonNull List<String> layoutNames) {
final Resources r = context.getResources();
- List<String> layoutNames = new ArrayList<>();
- selectedLayouts.forEach(
- (layoutDesc) -> layoutNames.add(getKeyboardLayout(layoutDesc).getLabel()));
Collections.sort(layoutNames);
switch (layoutNames.size()) {
case 1:
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index e1aa3a2..b229819 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -96,6 +96,32 @@
@GuardedBy("ImfLock.class") private int mDisplayIdToShowIme = INVALID_DISPLAY;
@GuardedBy("ImfLock.class") private int mDeviceIdToShowIme = DEVICE_ID_DEFAULT;
+ /**
+ * A set of status bits regarding the active IME.
+ *
+ * <p>This value is a combination of following two bits:</p>
+ * <dl>
+ * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
+ * <dd>
+ * If this bit is ON, connected IME is ready to accept touch/key events.
+ * </dd>
+ * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
+ * <dd>
+ * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
+ * </dd>
+ * <dt>{@link InputMethodService#IME_INVISIBLE}</dt>
+ * <dd> If this bit is ON, IME is ready with views from last EditorInfo but is
+ * currently invisible.
+ * </dd>
+ * </dl>
+ * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
+ * {@link InputMethodBindingController#unbindCurrentMethod()}.</em>
+ */
+ @GuardedBy("ImfLock.class") private int mImeWindowVis;
+
+ @GuardedBy("ImfLock.class")
+ private int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
+
@Nullable private CountDownLatch mLatchForTesting;
/**
@@ -473,7 +499,7 @@
if (getCurToken() != null) {
removeCurrentToken();
- mService.resetSystemUiLocked();
+ mService.resetSystemUiLocked(this);
mAutofillController.onResetSystemUi();
}
@@ -662,4 +688,24 @@
int getUserId() {
return mUserId;
}
+
+ @GuardedBy("ImfLock.class")
+ void setImeWindowVis(int imeWindowVis) {
+ mImeWindowVis = imeWindowVis;
+ }
+
+ @GuardedBy("ImfLock.class")
+ int getImeWindowVis() {
+ return mImeWindowVis;
+ }
+
+ @GuardedBy("ImfLock.class")
+ int getBackDisposition() {
+ return mBackDisposition;
+ }
+
+ @GuardedBy("ImfLock.class")
+ void setBackDisposition(int backDisposition) {
+ mBackDisposition = backDisposition;
+ }
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index ead7eb2..5228be4 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -320,6 +320,19 @@
&& Flags.concurrentInputMethods();
}
+ /**
+ * Figures out the target IME user ID for a given {@link Binder} IPC.
+ *
+ * @param callingProcessUserId the user ID of the calling process
+ * @return User ID to be used for this {@link Binder} call.
+ */
+ @GuardedBy("ImfLock.class")
+ @UserIdInt
+ @BinderThread
+ private int resolveImeUserIdLocked(@UserIdInt int callingProcessUserId) {
+ return mExperimentalConcurrentMultiUserModeEnabled ? callingProcessUserId : mCurrentUserId;
+ }
+
final Context mContext;
final Resources mRes;
private final Handler mHandler;
@@ -539,33 +552,6 @@
@MultiUserUnawareField
boolean mIsInteractive = true;
- @MultiUserUnawareField
- int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
-
- /**
- * A set of status bits regarding the active IME.
- *
- * <p>This value is a combination of following two bits:</p>
- * <dl>
- * <dt>{@link InputMethodService#IME_ACTIVE}</dt>
- * <dd>
- * If this bit is ON, connected IME is ready to accept touch/key events.
- * </dd>
- * <dt>{@link InputMethodService#IME_VISIBLE}</dt>
- * <dd>
- * If this bit is ON, some of IME view, e.g. software input, candidate view, is visible.
- * </dd>
- * <dt>{@link InputMethodService#IME_INVISIBLE}</dt>
- * <dd> If this bit is ON, IME is ready with views from last EditorInfo but is
- * currently invisible.
- * </dd>
- * </dl>
- * <em>Do not update this value outside of {@link #setImeWindowStatus(IBinder, int, int)} and
- * {@link InputMethodBindingController#unbindCurrentMethod()}.</em>
- */
- @MultiUserUnawareField
- int mImeWindowVis;
-
@SharedByAllUsersField
private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
@@ -923,7 +909,9 @@
// Uh oh, current input method is no longer around!
// Pick another one...
Slog.i(TAG, "Current input method removed: " + curInputMethodId);
- updateSystemUiLocked(0 /* vis */, mBackDisposition);
+ final var bindingController = getInputMethodBindingController(userId);
+ updateSystemUiLocked(0 /* vis */,
+ bindingController.getBackDisposition(), userId);
if (!chooseNewDefaultIMELocked()) {
changed = true;
curIm = null;
@@ -1399,7 +1387,9 @@
mStatusBarManagerInternal =
LocalServices.getService(StatusBarManagerInternal.class);
hideStatusBarIconLocked();
- updateSystemUiLocked(mImeWindowVis, mBackDisposition);
+ final var bindingController = getInputMethodBindingController(currentUserId);
+ updateSystemUiLocked(bindingController.getImeWindowVis(),
+ bindingController.getBackDisposition(), currentUserId);
mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
com.android.internal.R.bool.show_ongoing_ime_switcher);
if (mShowOngoingImeSwitcherForPhones) {
@@ -2413,11 +2403,13 @@
}
@GuardedBy("ImfLock.class")
- void resetSystemUiLocked() {
+ void resetSystemUiLocked(InputMethodBindingController bindingController) {
// Set IME window status as invisible when unbinding current method.
- mImeWindowVis = 0;
- mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
- updateSystemUiLocked(mImeWindowVis, mBackDisposition);
+ final int imeWindowVis = 0;
+ final int backDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
+ bindingController.setImeWindowVis(imeWindowVis);
+ bindingController.setBackDisposition(backDisposition);
+ updateSystemUiLocked(imeWindowVis, backDisposition, bindingController.getUserId());
}
@GuardedBy("ImfLock.class")
@@ -2531,7 +2523,12 @@
sessionState.mSession.finishSession();
} catch (RemoteException e) {
Slog.w(TAG, "Session failed to close due to remote exception", e);
- updateSystemUiLocked(0 /* vis */, mBackDisposition);
+ // TODO(b/350386877): Propagate userId from the caller or infer it from
+ // sessionState
+ final int userId = mCurrentUserId;
+ final var bindingController = getInputMethodBindingController(userId);
+ updateSystemUiLocked(0 /* vis */, bindingController.getBackDisposition(),
+ userId);
}
sessionState.mSession = null;
}
@@ -2751,8 +2748,8 @@
if (tokenDisplayId != topFocusedDisplayId && tokenDisplayId != FALLBACK_DISPLAY_ID) {
return;
}
- mImeWindowVis = vis;
- mBackDisposition = backDisposition;
+ bindingController.setImeWindowVis(vis);
+ bindingController.setBackDisposition(backDisposition);
updateSystemUiLocked(vis, backDisposition, userId);
}
@@ -2789,23 +2786,23 @@
private void updateImeWindowStatus(boolean disableImeIcon) {
synchronized (ImfLock.class) {
+ // TODO(b/350386877): Propagate userId from the caller.
+ final int userId = mCurrentUserId;
if (disableImeIcon) {
- updateSystemUiLocked(0, mBackDisposition);
+ final var bindingController = getInputMethodBindingController(userId);
+ updateSystemUiLocked(0, bindingController.getBackDisposition(), userId);
} else {
- updateSystemUiLocked();
+ updateSystemUiLocked(userId);
}
}
}
- @GuardedBy("ImfLock.class")
- void updateSystemUiLocked() {
- updateSystemUiLocked(mImeWindowVis, mBackDisposition);
- }
-
// Caution! This method is called in this class. Handle multi-user carefully
@GuardedBy("ImfLock.class")
- private void updateSystemUiLocked(int vis, int backDisposition) {
- updateSystemUiLocked(vis, backDisposition, mCurrentUserId);
+ void updateSystemUiLocked(@UserIdInt int userId) {
+ final var bindingController = getInputMethodBindingController(userId);
+ updateSystemUiLocked(bindingController.getImeWindowVis(),
+ bindingController.getBackDisposition(), userId);
}
@GuardedBy("ImfLock.class")
@@ -2916,6 +2913,9 @@
final var userData = getUserData(userId);
userData.mSwitchingController.resetCircularListLocked(mContext, settings);
userData.mHardwareKeyboardShortcutController.update(settings);
+
+ final var bindingController = getInputMethodBindingController(userId);
+ bindingController.setSelectedMethodId(id);
}
@GuardedBy("ImfLock.class")
@@ -3052,7 +3052,8 @@
setSelectedInputMethodAndSubtypeLocked(info, subtypeId, true, userId);
IInputMethodInvoker curMethod = bindingController.getCurMethod();
if (curMethod != null) {
- updateSystemUiLocked(mImeWindowVis, mBackDisposition);
+ updateSystemUiLocked(bindingController.getImeWindowVis(),
+ bindingController.getBackDisposition(), userId);
curMethod.changeInputMethodSubtype(newSubtype);
}
}
@@ -3101,19 +3102,19 @@
int lastClickToolType, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput");
- int uid = Binder.getCallingUid();
+ final int uid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(uid);
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#showSoftInput", mDumper);
synchronized (ImfLock.class) {
- if (!canInteractWithImeLocked(uid, client, "showSoftInput", statsToken)) {
+ final int userId = resolveImeUserIdLocked(callingUserId);
+ if (!canInteractWithImeLocked(uid, client, "showSoftInput", statsToken,
+ userId)) {
ImeTracker.forLogging().onFailed(
statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return false;
}
- // TODO(b/305849394): Create a utility method for the following policy.
- final int userId = mExperimentalConcurrentMultiUserModeEnabled
- ? UserHandle.getCallingUserId() : mCurrentUserId;
final long ident = Binder.clearCallingIdentity();
final var userData = getUserData(userId);
try {
@@ -3265,13 +3266,15 @@
try {
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#startStylusHandwriting", mDumper);
- int uid = Binder.getCallingUid();
+ final int uid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(uid);
synchronized (ImfLock.class) {
+ final int userId = resolveImeUserIdLocked(callingUserId);
if (!acceptingDelegation) {
mHwController.clearPendingHandwritingDelegation();
}
if (!canInteractWithImeLocked(uid, client, "startStylusHandwriting",
- null /* statsToken */)) {
+ null /* statsToken */, userId)) {
return false;
}
if (!hasSupportedStylusLocked()) {
@@ -3281,7 +3284,7 @@
}
final long ident = Binder.clearCallingIdentity();
try {
- final var bindingController = getInputMethodBindingController(mCurrentUserId);
+ final var bindingController = getInputMethodBindingController(userId);
if (!bindingController.supportsStylusHandwriting()) {
Slog.w(TAG,
"Stylus HW unsupported by IME. Ignoring startStylusHandwriting()");
@@ -3437,7 +3440,7 @@
return;
}
mFocusedWindowPerceptible.put(windowToken, windowPerceptible);
- updateSystemUiLocked();
+ updateSystemUiLocked(mCurrentUserId);
}
});
}
@@ -3531,11 +3534,13 @@
public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,
@NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
- int uid = Binder.getCallingUid();
+ final int uid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(uid);
ImeTracing.getInstance().triggerManagerServiceDump(
"InputMethodManagerService#hideSoftInput", mDumper);
synchronized (ImfLock.class) {
- if (!canInteractWithImeLocked(uid, client, "hideSoftInput", statsToken)) {
+ final int userId = resolveImeUserIdLocked(callingUserId);
+ if (!canInteractWithImeLocked(uid, client, "hideSoftInput", statsToken, userId)) {
if (isInputShownLocked()) {
ImeTracker.forLogging().onFailed(
statsToken, ImeTracker.PHASE_SERVER_CLIENT_FOCUSED);
@@ -3545,9 +3550,6 @@
}
return false;
}
- // TODO(b/305849394): Create a utility method for the following policy.
- final int userId = mExperimentalConcurrentMultiUserModeEnabled
- ? UserHandle.getCallingUserId() : mCurrentUserId;
final long ident = Binder.clearCallingIdentity();
final var userData = getUserData(userId);
try {
@@ -3582,9 +3584,9 @@
@Override
@IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)
public void hideSoftInputFromServerForTest() {
+ final int callingUserId = UserHandle.getCallingUserId();
synchronized (ImfLock.class) {
- // TODO(b/305849394): Get userId from caller.
- final int userId = mCurrentUserId;
+ final int userId = resolveImeUserIdLocked(callingUserId);
final var userData = getUserData(userId);
hideCurrentInputLocked(userData.mImeBindingState.mFocusedWindow, 0 /* flags */,
SoftInputShowHideReason.HIDE_SOFT_INPUT, userId);
@@ -3604,29 +3606,30 @@
boolean hideCurrentInputLocked(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
@InputMethodManager.HideFlags int flags, @Nullable ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason, @UserIdInt int userId) {
+ final var bindingController = getInputMethodBindingController(userId);
if (!mVisibilityStateComputer.canHideIme(statsToken, flags)) {
return false;
}
// There is a chance that IMM#hideSoftInput() is called in a transient state where
- // IMMS#InputShown is already updated to be true whereas IMMS#mImeWindowVis is still waiting
- // to be updated with the new value sent from IME process. Even in such a transient state
- // historically we have accepted an incoming call of IMM#hideSoftInput() from the
+ // IMMS#InputShown is already updated to be true whereas the user's ImeWindowVis is still
+ // waiting to be updated with the new value sent from IME process. Even in such a transient
+ // state historically we have accepted an incoming call of IMM#hideSoftInput() from the
// application process as a valid request, and have even promised such a behavior with CTS
// since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only
// IMMS#InputShown indicates that the software keyboard is shown.
// TODO(b/246309664): Clean up IMMS#mImeWindowVis
- final var bindingController = getInputMethodBindingController(userId);
final var userData = getUserData(userId);
IInputMethodInvoker curMethod = bindingController.getCurMethod();
final boolean shouldHideSoftInput = curMethod != null
- && (isInputShownLocked() || (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0);
+ && (isInputShownLocked()
+ || (bindingController.getImeWindowVis() & InputMethodService.IME_ACTIVE) != 0);
mVisibilityStateComputer.requestImeVisibility(windowToken, false);
if (shouldHideSoftInput) {
// The IME will report its visible state again after the following message finally
// delivered to the IME process as an IPC. Hence the inconsistency between
- // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
+ // IMMS#mInputShown and the user's ImeWindowVis should be resolved spontaneously in
// the final state.
ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_SERVER_SHOULD_HIDE);
mVisibilityApplier.performHideIme(windowToken, statsToken, resultReceiver, reason,
@@ -3945,9 +3948,7 @@
@GuardedBy("ImfLock.class")
private boolean canInteractWithImeLocked(int uid, IInputMethodClient client, String methodName,
- @Nullable ImeTracker.Token statsToken) {
- // TODO(b/305849394): Get userId from callers.
- final int userId = mCurrentUserId;
+ @Nullable ImeTracker.Token statsToken, @UserIdInt int userId) {
final var userData = getUserData(userId);
if (userData.mCurClient == null || client == null
|| userData.mCurClient.mClient.asBinder() != client.asBinder()) {
@@ -3994,15 +3995,14 @@
@Override
public void showInputMethodPickerFromClient(IInputMethodClient client,
int auxiliarySubtypeMode) {
+ final int callingUserId = UserHandle.getCallingUserId();
synchronized (ImfLock.class) {
if (!canShowInputMethodPickerLocked(client)) {
Slog.w(TAG, "Ignoring showInputMethodPickerFromClient of uid "
+ Binder.getCallingUid() + ": " + client);
return;
}
- // TODO(b/305849394): Create a utility method for the following policy.
- final int userId = mExperimentalConcurrentMultiUserModeEnabled
- ? UserHandle.getCallingUserId() : mCurrentUserId;
+ final int userId = resolveImeUserIdLocked(callingUserId);
final var userData = getUserData(userId);
// Always call subtype picker, because subtype picker is a superset of input method
// picker.
@@ -4045,7 +4045,7 @@
if (!calledWithValidTokenLocked(token, userId)) {
return;
}
- final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
final InputMethodInfo imi = settings.getMethodMap().get(id);
if (imi == null || !canCallerAccessInputMethod(
imi.getPackageName(), callingUid, userId, settings)) {
@@ -4063,7 +4063,7 @@
if (!calledWithValidTokenLocked(token, userId)) {
return;
}
- final InputMethodSettings settings = InputMethodSettingsRepository.get(mCurrentUserId);
+ final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
final InputMethodInfo imi = settings.getMethodMap().get(id);
if (imi == null || !canCallerAccessInputMethod(
imi.getPackageName(), callingUid, userId, settings)) {
@@ -4318,13 +4318,11 @@
return Binder.withCleanCallingIdentity(() -> {
final int curTokenDisplayId;
synchronized (ImfLock.class) {
+ final int userId = resolveImeUserIdLocked(callingUserId);
if (!canInteractWithImeLocked(callingUid, client,
- "getInputMethodWindowVisibleHeight", null /* statsToken */)) {
+ "getInputMethodWindowVisibleHeight", null /* statsToken */, userId)) {
return 0;
}
- // TODO(b/305849394): Create a utility method for the following policy.
- final int userId = mExperimentalConcurrentMultiUserModeEnabled
- ? callingUserId : mCurrentUserId;
final var bindingController = getInputMethodBindingController(userId);
// This should probably use the caller's display id, but because this is unsupported
// and maintained only for compatibility, there's no point in fixing it.
@@ -4453,10 +4451,12 @@
@IInputMethodManagerImpl.PermissionVerified(Manifest.permission.TEST_INPUT_METHOD)
@Override
public void addVirtualStylusIdForTestSession(IInputMethodClient client) {
- int uid = Binder.getCallingUid();
+ final int uid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(uid);
synchronized (ImfLock.class) {
+ final int userId = resolveImeUserIdLocked(callingUserId);
if (!canInteractWithImeLocked(uid, client, "addVirtualStylusIdForTestSession",
- null /* statsToken */)) {
+ null /* statsToken */, userId)) {
return;
}
final long ident = Binder.clearCallingIdentity();
@@ -4480,10 +4480,12 @@
@Override
public void setStylusWindowIdleTimeoutForTest(
IInputMethodClient client, @DurationMillisLong long timeout) {
- int uid = Binder.getCallingUid();
+ final int uid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(uid);
synchronized (ImfLock.class) {
+ final int userId = resolveImeUserIdLocked(callingUserId);
if (!canInteractWithImeLocked(uid, client, "setStylusWindowIdleTimeoutForTest",
- null /* statsToken */)) {
+ null /* statsToken */, userId)) {
return;
}
final long ident = Binder.clearCallingIdentity();
@@ -4617,8 +4619,8 @@
proto.write(HAVE_CONNECTION, bindingController.hasMainConnection());
proto.write(BOUND_TO_METHOD, userData.mBoundToMethod);
proto.write(IS_INTERACTIVE, mIsInteractive);
- proto.write(BACK_DISPOSITION, mBackDisposition);
- proto.write(IME_WINDOW_VISIBILITY, mImeWindowVis);
+ proto.write(BACK_DISPOSITION, bindingController.getBackDisposition());
+ proto.write(IME_WINDOW_VISIBILITY, bindingController.getImeWindowVis());
proto.write(SHOW_IME_WITH_HARD_KEYBOARD, mMenuController.getShowImeWithHardKeyboard());
proto.end(token);
}
@@ -5127,18 +5129,18 @@
private void handleSetInteractive(final boolean interactive) {
synchronized (ImfLock.class) {
- mIsInteractive = interactive;
- updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
-
// TODO(b/305849394): Support multiple IMEs.
- final var userId = mCurrentUserId;
+ final int userId = mCurrentUserId;
+ final var bindingController = getInputMethodBindingController(userId);
+ mIsInteractive = interactive;
+ updateSystemUiLocked(
+ interactive ? bindingController.getImeWindowVis() : 0,
+ bindingController.getBackDisposition(), userId);
final var userData = getUserData(userId);
// Inform the current client of the change in active status
if (userData.mCurClient == null || userData.mCurClient.mClient == null) {
return;
}
- // TODO(b/325515685): user data must be retrieved by a userId parameter
- final var bindingController = getInputMethodBindingController(mCurrentUserId);
if (mImePlatformCompatUtils.shouldUseSetInteractiveProtocol(
bindingController.getCurMethodUid())) {
// Handle IME visibility when interactive changed before finishing the input to
@@ -6157,7 +6159,19 @@
p.println(" hasMainConnection="
+ u.mBindingController.hasMainConnection());
p.println(" isVisibleBound=" + u.mBindingController.isVisibleBound());
- p.println(" mSwitchingController:");
+ p.println(" boundToMethod=" + u.mBoundToMethod);
+ p.println(" curClient=" + u.mCurClient);
+ if (u.mCurEditorInfo != null) {
+ p.println(" curEditorInfo:");
+ u.mCurEditorInfo.dump(p, " ", false /* dumpExtras */);
+ } else {
+ p.println(" curEditorInfo: null");
+ }
+ p.println(" imeBindingState:");
+ u.mImeBindingState.dump(" ", p);
+ p.println(" enabledSession=" + u.mEnabledSession);
+ p.println(" inFullscreenMode=" + u.mInFullscreenMode);
+ p.println(" switchingController:");
u.mSwitchingController.dump(p, " ");
};
mUserDataRepository.forAllUserData(userDataDump);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index 89a31e7..154ee1d 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -201,7 +201,7 @@
attrs.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
attrs.setTitle("Select input method");
w.setAttributes(attrs);
- mService.updateSystemUiLocked();
+ mService.updateSystemUiLocked(userId);
mService.sendOnNavButtonFlagsChangedLocked();
mSwitchingDialog.show();
}
@@ -239,7 +239,9 @@
mSwitchingDialog = null;
mSwitchingDialogTitleView = null;
- mService.updateSystemUiLocked();
+ // TODO(b/305849394): Make InputMethodMenuController multi-user aware
+ final int userId = mService.getCurrentImeUserIdLocked();
+ mService.updateSystemUiLocked(userId);
mService.sendOnNavButtonFlagsChangedLocked();
mDialogBuilder = null;
mIms = null;
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index 3051379..1a449e0 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -618,12 +618,14 @@
/**
* Processes message transactions, starting and completing them as needed.
+ * <p>
* This function is called when adding a message transaction or when a timer
* expires for an existing message transaction's retry or timeout. The
* internal processing loop will iterate at most twice as if one iteration
* completes a transaction, the next iteration can only start new transactions.
* If the first iteration does not complete any transaction, the loop will
* only iterate once.
+ * <p>
*/
private synchronized void processMessageTransactions() {
if (!Flags.reliableMessageRetrySupportService()) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index e0e8a03..e215ca3 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -5975,6 +5975,7 @@
@VisibleForTesting
void removeUserInfo(@UserIdInt int userId) {
synchronized (mUsersLock) {
+ UserManager.invalidateUserSerialNumberCache();
mUsers.remove(userId);
}
}
@@ -6400,6 +6401,7 @@
// Remove this user from the list
synchronized (mUsersLock) {
+ UserManager.invalidateUserSerialNumberCache();
mUsers.remove(userId);
mIsUserManaged.delete(userId);
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 57ea233..4d07ab5 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -807,7 +807,7 @@
getDefaultSystemHandlerActivityPackage(pm,
SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
userId, MICROPHONE_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
- NOTIFICATION_PERMISSIONS, PHONE_PERMISSIONS, CALENDAR_PERMISSIONS);
+ NOTIFICATION_PERMISSIONS);
}
// Voice recognition
@@ -875,6 +875,12 @@
getDefaultSystemHandlerActivityPackage(pm, ACTION_TRACK, userId), userId,
SENSORS_PERMISSIONS);
}
+
+ // Allow voice search on wear
+ grantPermissionsToSystemPackage(pm,
+ getDefaultSystemHandlerActivityPackage(pm,
+ SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId),
+ userId, PHONE_PERMISSIONS, CALENDAR_PERMISSIONS);
}
// Print Spooler
diff --git a/services/core/java/com/android/server/stats/pull/BatteryHealthUtility.java b/services/core/java/com/android/server/stats/pull/BatteryHealthUtility.java
new file mode 100644
index 0000000..e0768fe
--- /dev/null
+++ b/services/core/java/com/android/server/stats/pull/BatteryHealthUtility.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ * 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.stats.pull;
+
+import android.util.StatsEvent;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Locale;
+
+/**
+ * Utility class to redact Battery Health data from HealthServiceWrapper
+ *
+ * @hide
+ */
+public abstract class BatteryHealthUtility {
+ /**
+ * Create a StatsEvent corresponding to the Battery Health data, the fields
+ * of which are redacted to preserve users' privacy.
+ * The redaction consists in truncating the timestamps to the Monday of the
+ * corresponding week, and reducing the battery serial into the last byte
+ * of its MD5.
+ */
+ public static StatsEvent buildStatsEvent(int atomTag,
+ android.hardware.health.BatteryHealthData data, int chargeStatus, int chargePolicy)
+ throws NoSuchAlgorithmException {
+ int manufacturingDate = secondsToWeekYYYYMMDD(data.batteryManufacturingDateSeconds);
+ int firstUsageDate = secondsToWeekYYYYMMDD(data.batteryFirstUsageSeconds);
+ long stateOfHealth = data.batteryStateOfHealth;
+ int partStatus = data.batteryPartStatus;
+ int serialHashTruncated = stringToIntHash(data.batterySerialNumber) & 0xFF; // Last byte
+
+ return FrameworkStatsLog.buildStatsEvent(atomTag, manufacturingDate, firstUsageDate,
+ (int) stateOfHealth, serialHashTruncated, partStatus, chargeStatus, chargePolicy);
+ }
+
+ private static int secondsToWeekYYYYMMDD(long seconds) {
+ Calendar calendar = Calendar.getInstance();
+ long millis = seconds * 1000L;
+
+ calendar.setTimeInMillis(millis);
+
+ // Truncate all date information, up to week, which is rounded to
+ // MONDAY
+ calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", Locale.US);
+
+ String formattedDate = sdf.format(calendar.getTime());
+
+ return Integer.parseInt(formattedDate);
+ }
+
+ private static int stringToIntHash(String data) throws NoSuchAlgorithmException {
+ if (data == null || data.isEmpty()) {
+ return 0;
+ }
+
+ MessageDigest digest = MessageDigest.getInstance("MD5");
+ byte[] hashBytes = digest.digest(data.getBytes());
+
+ // Convert to integer (simplest way, but potential for loss of information)
+ BigInteger bigInt = new BigInteger(1, hashBytes);
+ return bigInt.intValue();
+ }
+}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index c1b825b..0041d39 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -119,6 +119,8 @@
import android.net.NetworkTemplate;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
+import android.os.BatteryManager;
+import android.os.BatteryProperty;
import android.os.BatteryStats;
import android.os.BatteryStatsInternal;
import android.os.BatteryStatsManager;
@@ -243,6 +245,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
@@ -769,6 +772,7 @@
case FrameworkStatsLog.FULL_BATTERY_CAPACITY:
case FrameworkStatsLog.BATTERY_VOLTAGE:
case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
+ case FrameworkStatsLog.BATTERY_HEALTH:
synchronized (mHealthHalLock) {
return pullHealthHalLocked(atomTag, data);
}
@@ -999,6 +1003,7 @@
registerFullBatteryCapacity();
registerBatteryVoltage();
registerBatteryCycleCount();
+ registerBatteryHealth();
registerSettingsStats();
registerInstalledIncrementalPackages();
registerKeystoreStorageStats();
@@ -4365,7 +4370,15 @@
);
}
- int pullHealthHalLocked(int atomTag, List<StatsEvent> pulledData) {
+ private void registerBatteryHealth() {
+ int tagId = FrameworkStatsLog.BATTERY_HEALTH;
+ mStatsManager.setPullAtomCallback(tagId,
+ null, // use default PullAtomMetadata values
+ DIRECT_EXECUTOR, mStatsCallbackImpl);
+ }
+
+ @GuardedBy("mHealthHalLock")
+ private int pullHealthHalLocked(int atomTag, List<StatsEvent> pulledData) {
if (mHealthService == null) {
return StatsManager.PULL_SKIP;
}
@@ -4396,6 +4409,44 @@
case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
pulledValue = healthInfo.batteryCycleCount;
break;
+ case FrameworkStatsLog.BATTERY_HEALTH:
+ android.hardware.health.BatteryHealthData bhd;
+ try {
+ bhd = mHealthService.getBatteryHealthData();
+ } catch (RemoteException | IllegalStateException e) {
+ return StatsManager.PULL_SKIP;
+ }
+ if (bhd == null) {
+ return StatsManager.PULL_SKIP;
+ }
+
+ StatsEvent batteryHealthEvent;
+ try {
+ BatteryProperty chargeStatusProperty = new BatteryProperty();
+ BatteryProperty chargePolicyProperty = new BatteryProperty();
+
+ if (0 > mHealthService.getProperty(
+ BatteryManager.BATTERY_PROPERTY_STATUS, chargeStatusProperty)) {
+ return StatsManager.PULL_SKIP;
+ }
+ if (0 > mHealthService.getProperty(
+ BatteryManager.BATTERY_PROPERTY_CHARGING_POLICY,
+ chargePolicyProperty)) {
+ return StatsManager.PULL_SKIP;
+ }
+ int chargeStatus = (int) chargeStatusProperty.getLong();
+ int chargePolicy = (int) chargePolicyProperty.getLong();
+ batteryHealthEvent = BatteryHealthUtility.buildStatsEvent(
+ atomTag, bhd, chargeStatus, chargePolicy);
+ pulledData.add(batteryHealthEvent);
+
+ return StatsManager.PULL_SUCCESS;
+ } catch (RemoteException | IllegalStateException e) {
+ Slog.e(TAG, "Failed to add pulled data", e);
+ } catch (NoSuchAlgorithmException e) {
+ Slog.e(TAG, "Could not find message digest algorithm", e);
+ }
+ return StatsManager.PULL_SKIP;
default:
return StatsManager.PULL_SKIP;
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 3e177c9..a8dcaa8 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -102,7 +102,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
import com.android.internal.policy.IKeyguardDismissCallback;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.Watchdog;
import com.android.server.pm.KnownPackages;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index dce496d..5f19924 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -386,7 +386,7 @@
import com.android.internal.os.TimeoutRecord;
import com.android.internal.os.TransferPipe;
import com.android.internal.policy.AttributeCache;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -8179,8 +8179,7 @@
}
void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
- if (mAppCompatController.getAppCompatOverrides()
- .getAppCompatOrientationOverrides()
+ if (mAppCompatController.getAppCompatOrientationOverrides()
.shouldIgnoreRequestedOrientation(requestedOrientation)) {
return;
}
@@ -8559,7 +8558,7 @@
final int parentWindowingMode =
newParentConfiguration.windowConfiguration.getWindowingMode();
final boolean isInCameraCompatFreeform = parentWindowingMode == WINDOWING_MODE_FREEFORM
- && mLetterboxUiController.getFreeformCameraCompatMode()
+ && mAppCompatController.getAppCompatCameraOverrides().getFreeformCameraCompatMode()
!= CAMERA_COMPAT_FREEFORM_NONE;
// Bubble activities should always fill their parent and should not be letterboxed.
@@ -9887,7 +9886,8 @@
return mLetterboxUiController.getUserMinAspectRatio();
}
if (!mLetterboxUiController.shouldOverrideMinAspectRatio()
- && !mLetterboxUiController.shouldOverrideMinAspectRatioForCamera()) {
+ && !mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera()) {
return info.getMinAspectRatio();
}
if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
@@ -10814,15 +10814,18 @@
proto.write(OVERRIDE_ORIENTATION, getOverrideOrientation());
proto.write(SHOULD_SEND_COMPAT_FAKE_FOCUS, shouldSendCompatFakeFocus());
proto.write(SHOULD_FORCE_ROTATE_FOR_CAMERA_COMPAT,
- mLetterboxUiController.shouldForceRotateForCameraCompat());
+ mAppCompatController.getAppCompatCameraOverrides()
+ .shouldForceRotateForCameraCompat());
proto.write(SHOULD_REFRESH_ACTIVITY_FOR_CAMERA_COMPAT,
- mLetterboxUiController.shouldRefreshActivityForCameraCompat());
+ mAppCompatController.getAppCompatCameraOverrides()
+ .shouldRefreshActivityForCameraCompat());
proto.write(SHOULD_REFRESH_ACTIVITY_VIA_PAUSE_FOR_CAMERA_COMPAT,
- mLetterboxUiController.shouldRefreshActivityViaPauseForCameraCompat());
+ mAppCompatController.getAppCompatCameraOverrides()
+ .shouldRefreshActivityViaPauseForCameraCompat());
proto.write(SHOULD_OVERRIDE_MIN_ASPECT_RATIO,
mLetterboxUiController.shouldOverrideMinAspectRatio());
proto.write(SHOULD_IGNORE_ORIENTATION_REQUEST_LOOP,
- mAppCompatController.getAppCompatOverrides().getAppCompatOrientationOverrides()
+ mAppCompatController.getAppCompatOrientationOverrides()
.shouldIgnoreOrientationRequestLoop());
proto.write(SHOULD_OVERRIDE_FORCE_RESIZE_APP,
mLetterboxUiController.shouldOverrideForceResizeApp());
diff --git a/services/core/java/com/android/server/wm/ActivityRefresher.java b/services/core/java/com/android/server/wm/ActivityRefresher.java
index 23a9708..0c32dfc 100644
--- a/services/core/java/com/android/server/wm/ActivityRefresher.java
+++ b/services/core/java/com/android/server/wm/ActivityRefresher.java
@@ -27,7 +27,7 @@
import android.os.Handler;
import android.os.RemoteException;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
@@ -77,10 +77,10 @@
final boolean cycleThroughStop =
mWmService.mLetterboxConfiguration
.isCameraCompatRefreshCycleThroughStopEnabled()
- && !activity.mLetterboxUiController
- .shouldRefreshActivityViaPauseForCameraCompat();
+ && !activity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldRefreshActivityViaPauseForCameraCompat();
- activity.mLetterboxUiController.setIsRefreshRequested(true);
+ activity.mAppCompatController.getAppCompatCameraOverrides().setIsRefreshRequested(true);
ProtoLog.v(WM_DEBUG_STATES,
"Refreshing activity for freeform camera compatibility treatment, "
+ "activityRecord=%s", activity);
@@ -97,24 +97,26 @@
}
}, REFRESH_CALLBACK_TIMEOUT_MS);
} catch (RemoteException e) {
- activity.mLetterboxUiController.setIsRefreshRequested(false);
+ activity.mAppCompatController.getAppCompatCameraOverrides()
+ .setIsRefreshRequested(false);
}
}
boolean isActivityRefreshing(@NonNull ActivityRecord activity) {
- return activity.mLetterboxUiController.isRefreshRequested();
+ return activity.mAppCompatController.getAppCompatCameraOverrides().isRefreshRequested();
}
void onActivityRefreshed(@NonNull ActivityRecord activity) {
// TODO(b/333060789): can we tell that refresh did not happen by observing the activity
// state?
- activity.mLetterboxUiController.setIsRefreshRequested(false);
+ activity.mAppCompatController.getAppCompatCameraOverrides().setIsRefreshRequested(false);
}
private boolean shouldRefreshActivity(@NonNull ActivityRecord activity,
@NonNull Configuration newConfig, @NonNull Configuration lastReportedConfig) {
return mWmService.mLetterboxConfiguration.isCameraCompatRefreshEnabled()
- && activity.mLetterboxUiController.shouldRefreshActivityForCameraCompat()
+ && activity.mAppCompatController.getAppCompatOverrides()
+ .getAppCompatCameraOverrides().shouldRefreshActivityForCameraCompat()
&& ArrayUtils.find(mEvaluators.toArray(), evaluator ->
((Evaluator) evaluator)
.shouldRefreshActivity(activity, newConfig, lastReportedConfig)) != null;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 717c399..5bfe9d7 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -127,7 +127,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
import com.android.server.pm.PackageArchiver;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 2109f5d..ded205e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -260,7 +260,7 @@
import com.android.internal.os.TransferPipe;
import com.android.internal.policy.AttributeCache;
import com.android.internal.policy.KeyguardDismissCallback;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
@@ -6192,11 +6192,14 @@
synchronized (mGlobalLockWithoutBoost) {
final WindowProcessController proc = mProcessNames.remove(name, uid);
if (proc != null && !mStartingProcessActivities.isEmpty()) {
- for (int i = mStartingProcessActivities.size() - 1; i >= 0; i--) {
- final ActivityRecord r = mStartingProcessActivities.get(i);
+ // Use a copy in case finishIfPossible changes the list indirectly.
+ final ArrayList<ActivityRecord> activities =
+ new ArrayList<>(mStartingProcessActivities);
+ for (int i = activities.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = activities.get(i);
if (uid == r.info.applicationInfo.uid && name.equals(r.processName)) {
Slog.w(TAG, proc + " is removed with pending start " + r);
- mStartingProcessActivities.remove(i);
+ mStartingProcessActivities.remove(r);
// If visible, finish it to avoid getting stuck on screen.
if (r.isVisibleRequested()) {
r.finishIfPossible("starting-proc-removed", false /* oomAdj */);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index cd5576f..d65a106 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -148,7 +148,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.ReferrerIntent;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
diff --git a/services/core/java/com/android/server/wm/AnrController.java b/services/core/java/com/android/server/wm/AnrController.java
index 0013c5c..80671ef 100644
--- a/services/core/java/com/android/server/wm/AnrController.java
+++ b/services/core/java/com/android/server/wm/AnrController.java
@@ -345,7 +345,7 @@
null /* processCpuTracker */, null /* lastPids */,
CompletableFuture.completedFuture(nativePids),
null /* logExceptionCreatingFile */, "Pre-dump", criticalEvents,
- Runnable::run, null/* AnrLatencyTracker */);
+ null /* extraHeaders */, Runnable::run, null/* AnrLatencyTracker */);
if (tracesFile != null) {
tracesFile.renameTo(
new File(tracesFile.getParent(), tracesFile.getName() + "_pre"));
diff --git a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
new file mode 100644
index 0000000..c0e5005
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
@@ -0,0 +1,235 @@
+/*
+ * 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.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
+import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
+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.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.annotation.NonNull;
+import android.app.CameraCompatTaskInfo.FreeformCameraCompatMode;
+
+import com.android.server.wm.utils.OptPropFactory;
+import com.android.window.flags.Flags;
+
+import java.util.function.BooleanSupplier;
+
+/**
+ * Encapsulates app compat configurations and overrides related to camera.
+ */
+class AppCompatCameraOverrides {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME
+ ? "AppCompatCameraOverrides" : TAG_ATM;
+
+ @NonNull
+ private final ActivityRecord mActivityRecord;
+ @NonNull
+ private final AppCompatCameraOverridesState mAppCompatCameraOverridesState;
+ @NonNull
+ private final LetterboxConfiguration mLetterboxConfiguration;
+ @NonNull
+ private final OptPropFactory.OptProp mAllowMinAspectRatioOverrideOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mCameraCompatAllowRefreshOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mCameraCompatEnableRefreshViaPauseOptProp;
+ @NonNull
+ private final OptPropFactory.OptProp mCameraCompatAllowForceRotationOptProp;
+
+ AppCompatCameraOverrides(@NonNull ActivityRecord activityRecord,
+ @NonNull LetterboxConfiguration letterboxConfiguration,
+ @NonNull OptPropFactory optPropBuilder) {
+ mActivityRecord = activityRecord;
+ mLetterboxConfiguration = letterboxConfiguration;
+ mAppCompatCameraOverridesState = new AppCompatCameraOverridesState();
+ mAllowMinAspectRatioOverrideOptProp = optPropBuilder.create(
+ PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE);
+ final BooleanSupplier isCameraCompatTreatmentEnabled = AppCompatUtils.asLazy(
+ mLetterboxConfiguration::isCameraCompatTreatmentEnabled);
+ mCameraCompatAllowRefreshOptProp = optPropBuilder.create(
+ PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH,
+ isCameraCompatTreatmentEnabled);
+ mCameraCompatEnableRefreshViaPauseOptProp = optPropBuilder.create(
+ PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE,
+ isCameraCompatTreatmentEnabled);
+ mCameraCompatAllowForceRotationOptProp = optPropBuilder.create(
+ PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION,
+ isCameraCompatTreatmentEnabled);
+ }
+
+ /**
+ * Whether we should apply the min aspect ratio per-app override only when an app is connected
+ * to the camera.
+ * When this override is applied the min aspect ratio given in the app's manifest will be
+ * overridden to the largest enabled aspect ratio treatment unless the app's manifest value
+ * is higher. The treatment will also apply if no value is provided in the manifest.
+ *
+ * <p>This method returns {@code true} when the following conditions are met:
+ * <ul>
+ * <li>Opt-out component property isn't enabled
+ * <li>Per-app override is enabled
+ * </ul>
+ */
+ boolean shouldOverrideMinAspectRatioForCamera() {
+ return mActivityRecord.isCameraActive()
+ && mAllowMinAspectRatioOverrideOptProp
+ .shouldEnableWithOptInOverrideAndOptOutProperty(
+ isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA));
+ }
+
+ /**
+ * Whether activity is eligible for activity "refresh" after camera compat force rotation
+ * treatment. See {@link DisplayRotationCompatPolicy} for context.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the camera compat treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override or by the app
+ * developers with the component property.
+ * </ul>
+ */
+ boolean shouldRefreshActivityForCameraCompat() {
+ return mCameraCompatAllowRefreshOptProp.shouldEnableWithOptOutOverrideAndProperty(
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH));
+ }
+
+ /**
+ * Whether activity should be "refreshed" after the camera compat force rotation treatment
+ * using the "resumed -> paused -> resumed" cycle rather than the "resumed -> ... -> stopped
+ * -> ... -> resumed" cycle. See {@link DisplayRotationCompatPolicy} for context.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the camera compat treatment is enabled.
+ * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle isn't disabled with the
+ * component property by the app developers.
+ * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle is enabled by the device
+ * manufacturer with override / by the app developers with the component property.
+ * </ul>
+ */
+ boolean shouldRefreshActivityViaPauseForCameraCompat() {
+ return mCameraCompatEnableRefreshViaPauseOptProp.shouldEnableWithOverrideAndProperty(
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE));
+ }
+
+ /**
+ * Whether activity is eligible for camera compat force rotation treatment. See {@link
+ * DisplayRotationCompatPolicy} for context.
+ *
+ * <p>This treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Flag gating the camera compat treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override or by the app
+ * developers with the component property.
+ * </ul>
+ */
+ boolean shouldForceRotateForCameraCompat() {
+ return mCameraCompatAllowForceRotationOptProp.shouldEnableWithOptOutOverrideAndProperty(
+ isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION));
+ }
+
+ /**
+ * Whether activity is eligible for camera compatibility free-form treatment.
+ *
+ * <p>The treatment is applied to a fixed-orientation camera activity in free-form windowing
+ * mode. The treatment letterboxes or pillarboxes the activity to the expected orientation and
+ * provides changes to the camera and display orientation signals to match those expected on a
+ * portrait device in that orientation (for example, on a standard phone).
+ *
+ * <p>The treatment is enabled when the following conditions are met:
+ * <ul>
+ * <li>Property gating the camera compatibility free-form treatment is enabled.
+ * <li>Activity isn't opted out by the device manufacturer with override.
+ * </ul>
+ */
+ boolean shouldApplyFreeformTreatmentForCameraCompat() {
+ return Flags.cameraCompatForFreeform() && !isCompatChangeEnabled(
+ OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);
+ }
+
+ /**
+ * @return {@code true} if the configuration needs to be recomputed after a camera state update.
+ */
+ boolean shouldRecomputeConfigurationForCameraCompat() {
+ return isOverrideOrientationOnlyForCameraEnabled()
+ || isCameraCompatSplitScreenAspectRatioAllowed()
+ || shouldOverrideMinAspectRatioForCamera();
+ }
+
+ boolean isOverrideOrientationOnlyForCameraEnabled() {
+ return isCompatChangeEnabled(OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA);
+ }
+
+ /**
+ * Whether activity "refresh" was requested but not finished in {@link #activityResumedLocked}.
+ */
+ boolean isRefreshRequested() {
+ return mAppCompatCameraOverridesState.mIsRefreshRequested;
+ }
+
+ /**
+ * @param isRequested Whether activity "refresh" was requested but not finished
+ * in {@link #activityResumedLocked}.
+ */
+ void setIsRefreshRequested(boolean isRequested) {
+ mAppCompatCameraOverridesState.mIsRefreshRequested = isRequested;
+ }
+
+ /**
+ * Whether we use split screen aspect ratio for the activity when camera compat treatment
+ * is active because the corresponding config is enabled and activity supports resizing.
+ */
+ boolean isCameraCompatSplitScreenAspectRatioAllowed() {
+ return mLetterboxConfiguration.isCameraCompatSplitScreenAspectRatioEnabled()
+ && !mActivityRecord.shouldCreateCompatDisplayInsets();
+ }
+
+ @FreeformCameraCompatMode
+ int getFreeformCameraCompatMode() {
+ return mAppCompatCameraOverridesState.mFreeformCameraCompatMode;
+ }
+
+ void setFreeformCameraCompatMode(@FreeformCameraCompatMode int freeformCameraCompatMode) {
+ mAppCompatCameraOverridesState.mFreeformCameraCompatMode = freeformCameraCompatMode;
+ }
+
+ private boolean isCompatChangeEnabled(long overrideChangeId) {
+ return mActivityRecord.info.isChangeEnabled(overrideChangeId);
+ }
+
+ static class AppCompatCameraOverridesState {
+ // Whether activity "refresh" was requested but not finished in
+ // ActivityRecord#activityResumedLocked following the camera compat force rotation in
+ // DisplayRotationCompatPolicy.
+ private boolean mIsRefreshRequested;
+
+ @FreeformCameraCompatMode
+ private int mFreeformCameraCompatMode = CAMERA_COMPAT_FREEFORM_NONE;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java b/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
new file mode 100644
index 0000000..ee523a2
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
@@ -0,0 +1,49 @@
+/*
+ * 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 com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.annotation.NonNull;
+
+/**
+ * Encapsulate the app compat logic related to camera.
+ */
+class AppCompatCameraPolicy {
+
+ private static final String TAG = TAG_WITH_CLASS_NAME
+ ? "AppCompatCameraPolicy" : TAG_ATM;
+
+ @NonNull
+ private final ActivityRecord mActivityRecord;
+
+ @NonNull
+ private final AppCompatCameraOverrides mAppCompatCameraOverrides;
+
+ AppCompatCameraPolicy(@NonNull ActivityRecord activityRecord,
+ @NonNull AppCompatCameraOverrides appCompatCameraOverrides) {
+ mActivityRecord = activityRecord;
+ mAppCompatCameraOverrides = appCompatCameraOverrides;
+ }
+
+ void recomputeConfigurationForCameraCompatIfNeeded() {
+ if (mAppCompatCameraOverrides.shouldRecomputeConfigurationForCameraCompat()) {
+ mActivityRecord.recomputeConfiguration();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java
index 4b0d739..d8c0c17 100644
--- a/services/core/java/com/android/server/wm/AppCompatController.java
+++ b/services/core/java/com/android/server/wm/AppCompatController.java
@@ -16,6 +16,9 @@
package com.android.server.wm;
import android.annotation.NonNull;
+import android.content.pm.PackageManager;
+
+import com.android.server.wm.utils.OptPropFactory;
/**
* Allows the interaction with all the app compat policies and configurations
@@ -28,19 +31,26 @@
private final AppCompatOrientationPolicy mOrientationPolicy;
@NonNull
private final AppCompatOverrides mAppCompatOverrides;
+ @NonNull
+ private final AppCompatCameraPolicy mAppCompatCameraPolicy;
AppCompatController(@NonNull WindowManagerService wmService,
@NonNull ActivityRecord activityRecord) {
+ final PackageManager packageManager = wmService.mContext.getPackageManager();
+ final OptPropFactory optPropBuilder = new OptPropFactory(packageManager,
+ activityRecord.packageName);
mTransparentPolicy = new TransparentPolicy(activityRecord,
wmService.mLetterboxConfiguration);
- mAppCompatOverrides = new AppCompatOverrides(wmService, activityRecord,
- wmService.mLetterboxConfiguration);
+ mAppCompatOverrides = new AppCompatOverrides(activityRecord,
+ wmService.mLetterboxConfiguration, optPropBuilder);
// TODO(b/341903757) Remove BooleanSuppliers after fixing dependency with aspectRatio.
final LetterboxUiController tmpController = activityRecord.mLetterboxUiController;
mOrientationPolicy = new AppCompatOrientationPolicy(activityRecord,
mAppCompatOverrides, tmpController::shouldApplyUserFullscreenOverride,
tmpController::shouldApplyUserMinAspectRatioOverride,
tmpController::isSystemOverrideToFullscreenEnabled);
+ mAppCompatCameraPolicy = new AppCompatCameraPolicy(activityRecord,
+ mAppCompatOverrides.getAppCompatCameraOverrides());
}
@NonNull
@@ -54,7 +64,22 @@
}
@NonNull
+ AppCompatCameraPolicy getAppCompatCameraPolicy() {
+ return mAppCompatCameraPolicy;
+ }
+
+ @NonNull
AppCompatOverrides getAppCompatOverrides() {
return mAppCompatOverrides;
}
+
+ @NonNull
+ AppCompatOrientationOverrides getAppCompatOrientationOverrides() {
+ return mAppCompatOverrides.getAppCompatOrientationOverrides();
+ }
+
+ @NonNull
+ AppCompatCameraOverrides getAppCompatCameraOverrides() {
+ return mAppCompatOverrides.getAppCompatCameraOverrides();
+ }
}
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java b/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
index 446a75c..b0fdbb5 100644
--- a/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
@@ -28,7 +28,7 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.AppCompatOverrides.asLazy;
+import static com.android.server.wm.AppCompatUtils.asLazy;
import android.annotation.NonNull;
import android.content.pm.ActivityInfo;
@@ -60,9 +60,9 @@
@NonNull
final OrientationOverridesState mOrientationOverridesState;
- AppCompatOrientationOverrides(@NonNull OptPropFactory optPropBuilder,
- @NonNull LetterboxConfiguration letterboxConfiguration,
- @NonNull ActivityRecord activityRecord) {
+ AppCompatOrientationOverrides(@NonNull ActivityRecord activityRecord,
+ @NonNull LetterboxConfiguration letterboxConfiguration,
+ @NonNull OptPropFactory optPropBuilder) {
mActivityRecord = activityRecord;
mOrientationOverridesState = new OrientationOverridesState(mActivityRecord,
System::currentTimeMillis);
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
index 8e9a9e9..960ef5a 100644
--- a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
@@ -103,11 +103,11 @@
return candidate;
}
- if (displayContent != null && mAppCompatOverrides
+ if (displayContent != null && mAppCompatOverrides.getAppCompatCameraOverrides()
.isOverrideOrientationOnlyForCameraEnabled()
- && (displayContent.mDisplayRotationCompatPolicy == null
- || !displayContent.mDisplayRotationCompatPolicy
- .isActivityEligibleForOrientationOverride(mActivityRecord))) {
+ && (displayContent.mDisplayRotationCompatPolicy == null
+ || !displayContent.mDisplayRotationCompatPolicy
+ .isActivityEligibleForOrientationOverride(mActivityRecord))) {
return candidate;
}
diff --git a/services/core/java/com/android/server/wm/AppCompatOverrides.java b/services/core/java/com/android/server/wm/AppCompatOverrides.java
index 794008a..c20da7c 100644
--- a/services/core/java/com/android/server/wm/AppCompatOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatOverrides.java
@@ -19,22 +19,13 @@
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_ANY_ORIENTATION_TO_USER;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
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_ORIENTATION_ONLY_FOR_CAMERA;
import static android.content.pm.ActivityInfo.OVERRIDE_RESPECT_REQUESTED_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_UNSET;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-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_DISPLAY_ORIENTATION_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE;
import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
@@ -47,12 +38,8 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import android.annotation.NonNull;
-import android.content.pm.PackageManager;
import com.android.server.wm.utils.OptPropFactory;
-import com.android.window.flags.Flags;
-
-import java.util.function.BooleanSupplier;
/**
* Encapsulate logic related to operations guarded by an app override.
@@ -70,12 +57,6 @@
@NonNull
private final OptPropFactory.OptProp mFakeFocusOptProp;
@NonNull
- private final OptPropFactory.OptProp mCameraCompatAllowForceRotationOptProp;
- @NonNull
- private final OptPropFactory.OptProp mCameraCompatAllowRefreshOptProp;
- @NonNull
- private final OptPropFactory.OptProp mCameraCompatEnableRefreshViaPauseOptProp;
- @NonNull
private final OptPropFactory.OptProp mAllowOrientationOverrideOptProp;
@NonNull
private final OptPropFactory.OptProp mAllowDisplayOrientationOverrideOptProp;
@@ -87,37 +68,25 @@
private final OptPropFactory.OptProp mAllowUserAspectRatioOverrideOptProp;
@NonNull
private final OptPropFactory.OptProp mAllowUserAspectRatioFullscreenOverrideOptProp;
-
+ @NonNull
private final AppCompatOrientationOverrides mAppCompatOrientationOverrides;
+ @NonNull
+ private final AppCompatCameraOverrides mAppCompatCameraOverrides;
- AppCompatOverrides(@NonNull WindowManagerService wmService,
- @NonNull ActivityRecord activityRecord,
- @NonNull LetterboxConfiguration letterboxConfiguration) {
+ AppCompatOverrides(@NonNull ActivityRecord activityRecord,
+ @NonNull LetterboxConfiguration letterboxConfiguration,
+ @NonNull OptPropFactory optPropBuilder) {
mLetterboxConfiguration = letterboxConfiguration;
mActivityRecord = activityRecord;
- final PackageManager packageManager = wmService.mContext.getPackageManager();
- final OptPropFactory optPropBuilder = new OptPropFactory(packageManager,
- activityRecord.packageName);
-
- mAppCompatOrientationOverrides =
- new AppCompatOrientationOverrides(optPropBuilder, mLetterboxConfiguration,
- mActivityRecord);
+ mAppCompatOrientationOverrides = new AppCompatOrientationOverrides(mActivityRecord,
+ mLetterboxConfiguration, optPropBuilder);
+ mAppCompatCameraOverrides = new AppCompatCameraOverrides(mActivityRecord,
+ mLetterboxConfiguration, optPropBuilder);
mFakeFocusOptProp = optPropBuilder.create(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS,
mLetterboxConfiguration::isCompatFakeFocusEnabled);
- final BooleanSupplier isCameraCompatTreatmentEnabled = asLazy(
- mLetterboxConfiguration::isCameraCompatTreatmentEnabled);
- mCameraCompatAllowForceRotationOptProp = optPropBuilder.create(
- PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION,
- isCameraCompatTreatmentEnabled);
- mCameraCompatAllowRefreshOptProp = optPropBuilder.create(
- PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH,
- isCameraCompatTreatmentEnabled);
- mCameraCompatEnableRefreshViaPauseOptProp = optPropBuilder.create(
- PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE,
- isCameraCompatTreatmentEnabled);
mAllowOrientationOverrideOptProp = optPropBuilder.create(
PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE);
@@ -162,6 +131,11 @@
return mAppCompatOrientationOverrides;
}
+ @NonNull
+ AppCompatCameraOverrides getAppCompatCameraOverrides() {
+ return mAppCompatCameraOverrides;
+ }
+
/**
* Whether sending compat fake focus for split screen resumed activities is enabled. Needed
* because some game engines wait to get focus before drawing the content of the app which isn't
@@ -179,57 +153,6 @@
isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS));
}
- /**
- * Whether activity is eligible for camera compat force rotation treatment. See {@link
- * DisplayRotationCompatPolicy} for context.
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the camera compat treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override or by the app
- * developers with the component property.
- * </ul>
- */
- boolean shouldForceRotateForCameraCompat() {
- return mCameraCompatAllowForceRotationOptProp.shouldEnableWithOptOutOverrideAndProperty(
- isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION));
- }
-
- /**
- * Whether activity is eligible for activity "refresh" after camera compat force rotation
- * treatment. See {@link DisplayRotationCompatPolicy} for context.
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the camera compat treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override or by the app
- * developers with the component property.
- * </ul>
- */
- boolean shouldRefreshActivityForCameraCompat() {
- return mCameraCompatAllowRefreshOptProp.shouldEnableWithOptOutOverrideAndProperty(
- isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH));
- }
-
- /**
- * Whether activity should be "refreshed" after the camera compat force rotation treatment
- * using the "resumed -> paused -> resumed" cycle rather than the "resumed -> ... -> stopped
- * -> ... -> resumed" cycle. See {@link DisplayRotationCompatPolicy} for context.
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the camera compat treatment is enabled.
- * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle isn't disabled with the
- * component property by the app developers.
- * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle is enabled by the device
- * manufacturer with override / by the app developers with the component property.
- * </ul>
- */
- boolean shouldRefreshActivityViaPauseForCameraCompat() {
- return mCameraCompatEnableRefreshViaPauseOptProp.shouldEnableWithOverrideAndProperty(
- isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE));
- }
-
boolean isSystemOverrideToFullscreenEnabled(int userAspectRatio) {
return isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION_TO_USER)
&& !mAllowOrientationOverrideOptProp.isFalse()
@@ -262,50 +185,6 @@
return isCompatChangeEnabled(OVERRIDE_RESPECT_REQUESTED_ORIENTATION);
}
- boolean isOverrideOrientationOnlyForCameraEnabled() {
- return isCompatChangeEnabled(OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA);
- }
-
- /**
- * Whether activity is eligible for camera compatibility free-form treatment.
- *
- * <p>The treatment is applied to a fixed-orientation camera activity in free-form windowing
- * mode. The treatment letterboxes or pillarboxes the activity to the expected orientation and
- * provides changes to the camera and display orientation signals to match those expected on a
- * portrait device in that orientation (for example, on a standard phone).
- *
- * <p>The treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Property gating the camera compatibility free-form treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override.
- * </ul>
- */
- boolean shouldApplyFreeformTreatmentForCameraCompat() {
- return Flags.cameraCompatForFreeform() && !isCompatChangeEnabled(
- OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);
- }
-
-
- /**
- * Whether we should apply the min aspect ratio per-app override only when an app is connected
- * to the camera.
- * When this override is applied the min aspect ratio given in the app's manifest will be
- * overridden to the largest enabled aspect ratio treatment unless the app's manifest value
- * is higher. The treatment will also apply if no value is provided in the manifest.
- *
- * <p>This method returns {@code true} when the following conditions are met:
- * <ul>
- * <li>Opt-out component property isn't enabled
- * <li>Per-app override is enabled
- * </ul>
- */
- boolean shouldOverrideMinAspectRatioForCamera() {
- return mActivityRecord.isCameraActive()
- && mAllowMinAspectRatioOverrideOptProp
- .shouldEnableWithOptInOverrideAndOptOutProperty(
- isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA));
- }
-
/**
* Whether should fix display orientation to landscape natural orientation when a task is
* fullscreen and the display is ignoring orientation requests.
@@ -382,21 +261,4 @@
private boolean isCompatChangeEnabled(long overrideChangeId) {
return mActivityRecord.info.isChangeEnabled(overrideChangeId);
}
-
- @NonNull
- static BooleanSupplier asLazy(@NonNull BooleanSupplier supplier) {
- return new BooleanSupplier() {
- private boolean mRead;
- private boolean mValue;
-
- @Override
- public boolean getAsBoolean() {
- if (!mRead) {
- mRead = true;
- mValue = supplier.getAsBoolean();
- }
- return mValue;
- }
- };
- }
}
diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java
new file mode 100644
index 0000000..be51dd3b
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppCompatUtils.java
@@ -0,0 +1,51 @@
+/*
+ * 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 android.annotation.NonNull;
+
+import java.util.function.BooleanSupplier;
+
+/**
+ * Utilities for App Compat policies and overrides.
+ */
+class AppCompatUtils {
+
+ /**
+ * Lazy version of a {@link BooleanSupplier} which access an existing BooleanSupplier and
+ * caches the value.
+ *
+ * @param supplier The BooleanSupplier to decorate.
+ * @return A lazy implementation of a BooleanSupplier
+ */
+ @NonNull
+ static BooleanSupplier asLazy(@NonNull BooleanSupplier supplier) {
+ return new BooleanSupplier() {
+ private boolean mRead;
+ private boolean mValue;
+
+ @Override
+ public boolean getAsBoolean() {
+ if (!mRead) {
+ mRead = true;
+ mValue = supplier.getAsBoolean();
+ }
+ return mValue;
+ }
+ };
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c2b9128..bc7e84a 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -135,7 +135,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.DumpUtils.Dump;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index c55a100..44b414f 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -92,7 +92,7 @@
import android.window.ITaskFragmentOrganizer;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index a8cc2ae..4554b21 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -30,7 +30,7 @@
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 14ae918..cb69039 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -61,7 +61,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java
index 0b2c851..ba4ab7d 100644
--- a/services/core/java/com/android/server/wm/BlackFrame.java
+++ b/services/core/java/com/android/server/wm/BlackFrame.java
@@ -22,7 +22,7 @@
import android.view.Surface.OutOfResourcesException;
import android.view.SurfaceControl;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
import java.util.function.Supplier;
diff --git a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
index 0c751cf..68a4172 100644
--- a/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
+++ b/services/core/java/com/android/server/wm/CameraCompatFreeformPolicy.java
@@ -32,7 +32,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
/**
@@ -110,12 +110,14 @@
if (!isTreatmentEnabledForActivity(cameraActivity)) {
return false;
}
- final int existingCameraCompatMode =
- cameraActivity.mLetterboxUiController.getFreeformCameraCompatMode();
+ final int existingCameraCompatMode = cameraActivity.mAppCompatController
+ .getAppCompatCameraOverrides()
+ .getFreeformCameraCompatMode();
final int newCameraCompatMode = getCameraCompatMode(cameraActivity);
if (newCameraCompatMode != existingCameraCompatMode) {
mIsCameraCompatTreatmentPending = true;
- cameraActivity.mLetterboxUiController.setFreeformCameraCompatMode(newCameraCompatMode);
+ cameraActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .setFreeformCameraCompatMode(newCameraCompatMode);
forceUpdateActivityAndTask(cameraActivity);
return true;
} else {
@@ -134,8 +136,8 @@
mDisplayContent.mDisplayId, cameraId);
return false;
}
- cameraActivity.mLetterboxUiController.setFreeformCameraCompatMode(
- CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE);
+ cameraActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .setFreeformCameraCompatMode(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE);
forceUpdateActivityAndTask(cameraActivity);
mIsCameraCompatTreatmentPending = false;
return true;
@@ -191,6 +193,6 @@
|| mCameraStateMonitor.isCameraWithIdRunningForActivity(topActivity, cameraId)) {
return false;
}
- return topActivity.mLetterboxUiController.isRefreshRequested();
+ return topActivity.mAppCompatController.getAppCompatCameraOverrides().isRefreshRequested();
}
}
diff --git a/services/core/java/com/android/server/wm/CameraStateMonitor.java b/services/core/java/com/android/server/wm/CameraStateMonitor.java
index ea7edea..a54141c 100644
--- a/services/core/java/com/android/server/wm/CameraStateMonitor.java
+++ b/services/core/java/com/android/server/wm/CameraStateMonitor.java
@@ -26,7 +26,7 @@
import android.util.ArraySet;
import android.util.Slog;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.ArrayList;
import java.util.List;
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index b795987f..44202a2 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -48,7 +48,7 @@
import android.util.SparseBooleanArray;
import android.util.Xml;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index d70a880..7e7073c 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -42,7 +42,7 @@
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.display.feature.DisplayManagerFlags;
/**
diff --git a/services/core/java/com/android/server/wm/ContentRecordingController.java b/services/core/java/com/android/server/wm/ContentRecordingController.java
index b589085..283f819 100644
--- a/services/core/java/com/android/server/wm/ContentRecordingController.java
+++ b/services/core/java/com/android/server/wm/ContentRecordingController.java
@@ -23,7 +23,7 @@
import android.view.ContentRecordingSession;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
/**
* Orchestrates the handoff between displays if the recording session changes, and keeps track of
diff --git a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
index be44629..3b99954 100644
--- a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
+++ b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
@@ -36,7 +36,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.display.BrightnessSynchronizer;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.wm.utils.DisplayInfoOverrides.DisplayInfoFieldsUpdater;
import com.android.window.flags.Flags;
diff --git a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
index 735c73a..22fa88f 100644
--- a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
+++ b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
@@ -29,7 +29,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 0006bd2..def495f 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -45,7 +45,7 @@
import android.window.IDisplayAreaOrganizer;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
index 3dc3be9..8f471d7 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -33,7 +33,7 @@
import android.window.IDisplayAreaOrganizerController;
import android.window.WindowContainerToken;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 8c52288..bb596cc 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -42,7 +42,7 @@
import com.android.internal.annotations.Keep;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7ffffe9..b5b9377 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -254,7 +254,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4a59fc2..b36fbd3 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -132,7 +132,7 @@
import com.android.internal.policy.ForceShowNavBarSettingsObserver;
import com.android.internal.policy.GestureNavigationSettingsObserver;
import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.statusbar.LetterboxDetails;
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.util.ScreenshotRequest;
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index afcf364..f3ccc3b 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -80,7 +80,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.policy.WindowManagerPolicy;
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index 6ecafdb..3d71e95 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -42,7 +42,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.UiThread;
/**
@@ -228,9 +228,11 @@
!= lastReportedConfig.windowConfiguration.getDisplayRotation());
return isTreatmentEnabledForDisplay()
&& isTreatmentEnabledForActivity(activity)
- && activity.mLetterboxUiController.shouldRefreshActivityForCameraCompat()
+ && activity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldRefreshActivityForCameraCompat()
&& (displayRotationChanged
- || activity.mLetterboxUiController.isCameraCompatSplitScreenAspectRatioAllowed());
+ || activity.mAppCompatController.getAppCompatCameraOverrides()
+ .isCameraCompatSplitScreenAspectRatioAllowed());
}
/**
@@ -254,7 +256,8 @@
boolean isActivityEligibleForOrientationOverride(@NonNull ActivityRecord activity) {
return isTreatmentEnabledForDisplay()
&& isCameraActive(activity, /* mustBeFullscreen */ true)
- && activity.mLetterboxUiController.shouldForceRotateForCameraCompat();
+ && activity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldForceRotateForCameraCompat();
}
/**
@@ -286,7 +289,8 @@
// handle dynamic changes so we shouldn't force rotate them.
&& activity.getOverrideOrientation() != SCREEN_ORIENTATION_NOSENSOR
&& activity.getOverrideOrientation() != SCREEN_ORIENTATION_LOCKED
- && activity.mLetterboxUiController.shouldForceRotateForCameraCompat();
+ && activity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldForceRotateForCameraCompat();
}
@Override
@@ -295,7 +299,8 @@
// Checking whether an activity in fullscreen rather than the task as this camera
// compat treatment doesn't cover activity embedding.
if (cameraActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
- cameraActivity.mLetterboxUiController.recomputeConfigurationForCameraCompatIfNeeded();
+ cameraActivity.mAppCompatController
+ .getAppCompatCameraPolicy().recomputeConfigurationForCameraCompatIfNeeded();
mDisplayContent.updateOrientation();
return true;
}
@@ -362,7 +367,8 @@
|| topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
return true;
}
- topActivity.mLetterboxUiController.recomputeConfigurationForCameraCompatIfNeeded();
+ topActivity.mAppCompatController
+ .getAppCompatCameraPolicy().recomputeConfigurationForCameraCompatIfNeeded();
mDisplayContent.updateOrientation();
return true;
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotationReversionController.java b/services/core/java/com/android/server/wm/DisplayRotationReversionController.java
index 50b29ec..f94b8c4 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationReversionController.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationReversionController.java
@@ -26,7 +26,7 @@
import android.content.ActivityInfoProto;
import android.view.Surface;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
/**
* Defines the behavior of reversion from device rotation overrides.
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
index c79565a..8bd8098 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.os.UserHandle.USER_SYSTEM;
import static android.view.Display.TYPE_VIRTUAL;
import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
@@ -27,6 +28,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.WindowConfiguration;
import android.os.Environment;
import android.util.ArrayMap;
@@ -42,6 +44,7 @@
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider;
+import com.android.window.flags.Flags;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -53,6 +56,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
+import java.util.Set;
/**
* Implementation of {@link SettingsProvider} that reads the base settings provided in a display
@@ -91,11 +95,11 @@
@NonNull
private ReadableSettings mBaseSettings;
@NonNull
- private final WritableSettings mOverrideSettings;
+ private WritableSettings mOverrideSettings;
DisplayWindowSettingsProvider() {
this(new AtomicFileStorage(getVendorSettingsFile()),
- new AtomicFileStorage(getOverrideSettingsFile()));
+ new AtomicFileStorage(getOverrideSettingsFileForUser(USER_SYSTEM)));
}
@VisibleForTesting
@@ -133,6 +137,48 @@
mBaseSettings = new ReadableSettings(baseSettingsStorage);
}
+ /**
+ * Overrides the storage that should be used to save override settings for a user.
+ *
+ * @see #DATA_DISPLAY_SETTINGS_FILE_PATH
+ */
+ void setOverrideSettingsForUser(@UserIdInt int userId) {
+ if (!Flags.perUserDisplayWindowSettings()) {
+ return;
+ }
+ final AtomicFile settingsFile = getOverrideSettingsFileForUser(userId);
+ setOverrideSettingsStorage(new AtomicFileStorage(settingsFile));
+ }
+
+ /**
+ * Removes display override settings that are no longer associated with active displays.
+ * This is necessary because displays can be dynamically added or removed during
+ * the system's lifecycle (e.g., user switch, system server restart).
+ *
+ * @param root The root window container used to obtain the currently active displays.
+ */
+ void removeStaleDisplaySettings(@NonNull RootWindowContainer root) {
+ if (!Flags.perUserDisplayWindowSettings()) {
+ return;
+ }
+ final Set<String> displayIdentifiers = new ArraySet<>();
+ root.forAllDisplays(dc -> {
+ final String identifier = mOverrideSettings.getIdentifier(dc.getDisplayInfo());
+ displayIdentifiers.add(identifier);
+ });
+ mOverrideSettings.removeStaleDisplaySettings(displayIdentifiers);
+ }
+
+ /**
+ * Overrides the storage that should be used to save override settings.
+ *
+ * @see #setOverrideSettingsForUser(int)
+ */
+ @VisibleForTesting
+ void setOverrideSettingsStorage(@NonNull WritableSettingsStorage overrideSettingsStorage) {
+ mOverrideSettings = new WritableSettings(overrideSettingsStorage);
+ }
+
@Override
@NonNull
public SettingsEntry getSettings(@NonNull DisplayInfo info) {
@@ -302,6 +348,12 @@
mVirtualDisplayIdentifiers.remove(identifier);
}
+ void removeStaleDisplaySettings(@NonNull Set<String> currentDisplayIdentifiers) {
+ if (mSettings.retainAll(currentDisplayIdentifiers)) {
+ writeSettings();
+ }
+ }
+
private void writeSettings() {
final FileData fileData = new FileData();
fileData.mIdentifierType = mIdentifierType;
@@ -332,9 +384,14 @@
}
@NonNull
- private static AtomicFile getOverrideSettingsFile() {
- final File overrideSettingsFile = new File(Environment.getDataDirectory(),
- DATA_DISPLAY_SETTINGS_FILE_PATH);
+ private static AtomicFile getOverrideSettingsFileForUser(@UserIdInt int userId) {
+ final File directory;
+ if (userId == USER_SYSTEM || !Flags.perUserDisplayWindowSettings()) {
+ directory = Environment.getDataDirectory();
+ } else {
+ directory = Environment.getDataSystemCeDirectory(userId);
+ }
+ final File overrideSettingsFile = new File(directory, DATA_DISPLAY_SETTINGS_FILE_PATH);
return new AtomicFile(overrideSettingsFile, WM_DISPLAY_COMMIT_TAG);
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index e3827aa..4be5bad 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -64,7 +64,7 @@
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.view.IDragAndDropPermissions;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index a21ba26..c66d659 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -35,7 +35,7 @@
import android.view.InputChannel;
import android.window.InputTransferToken;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.input.InputManagerService;
/**
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 156e9f9..91c61b1 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -40,7 +40,7 @@
import android.view.inputmethod.ImeTracker;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 8035a29..74dbd15 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -66,7 +66,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.SoftInputShowHideReason;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.inputmethod.InputMethodManagerInternal;
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index f68b67f6..33dea54 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -48,7 +48,7 @@
import android.view.WindowInsets;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.TriFunction;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index a967f7a..3483842 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -41,7 +41,7 @@
import android.view.WindowInsets;
import android.view.WindowInsets.Type.InsetsType;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.inputmethod.InputMethodManagerInternal;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index f70d2a5..872b4e1 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_APPEARING;
@@ -657,7 +656,6 @@
final boolean lastKeyguardGoingAway = mKeyguardGoingAway;
final ActivityRecord lastDismissKeyguardActivity = mDismissingKeyguardActivity;
- final ActivityRecord lastTurnScreenOnActivity = mTopTurnScreenOnActivity;
mRequestDismissKeyguard = false;
mOccluded = false;
@@ -666,7 +664,6 @@
mDismissingKeyguardActivity = null;
mTopTurnScreenOnActivity = null;
- boolean occludedByActivity = false;
final Task task = getRootTaskForControllingOccluding(display);
final ActivityRecord top = task != null ? task.getTopNonFinishingActivity() : null;
if (top != null) {
@@ -712,7 +709,7 @@
if (mTopTurnScreenOnActivity != null
&& !mService.mWindowManager.mPowerManager.isInteractive()
- && (mRequestDismissKeyguard || occludedByActivity)) {
+ && (mRequestDismissKeyguard || mOccluded)) {
controller.mTaskSupervisor.wakeUp("handleTurnScreenOn");
mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false);
}
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 85eeab1..e924fb6 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_16_9;
@@ -65,7 +64,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager.TaskDescription;
-import android.app.CameraCompatTaskInfo.FreeformCameraCompatMode;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -113,18 +111,10 @@
@Nullable
private Letterbox mLetterbox;
- // Whether activity "refresh" was requested but not finished in
- // ActivityRecord#activityResumedLocked following the camera compat force rotation in
- // DisplayRotationCompatPolicy.
- private boolean mIsRefreshRequested;
-
private boolean mLastShouldShowLetterboxUi;
private boolean mDoubleTapEvent;
- @FreeformCameraCompatMode
- private int mFreeformCameraCompatMode = CAMERA_COMPAT_FREEFORM_NONE;
-
LetterboxUiController(WindowManagerService wmService, ActivityRecord activityRecord) {
mLetterboxConfiguration = wmService.mLetterboxConfiguration;
// Given activityRecord may not be fully constructed since LetterboxUiController
@@ -147,13 +137,6 @@
}
}
-
- @VisibleForTesting
- int getSetOrientationRequestCounter() {
- return getAppCompatOverrides().getAppCompatOrientationOverrides()
- .getSetOrientationRequestCounter();
- }
-
/**
* Whether sending compat fake focus for split screen resumed activities is enabled. Needed
* because some game engines wait to get focus before drawing the content of the app which isn't
@@ -187,23 +170,6 @@
}
/**
- * Whether we should apply the min aspect ratio per-app override only when an app is connected
- * to the camera.
- * When this override is applied the min aspect ratio given in the app's manifest will be
- * overridden to the largest enabled aspect ratio treatment unless the app's manifest value
- * is higher. The treatment will also apply if no value is provided in the manifest.
- *
- * <p>This method returns {@code true} when the following conditions are met:
- * <ul>
- * <li>Opt-out component property isn't enabled
- * <li>Per-app override is enabled
- * </ul>
- */
- boolean shouldOverrideMinAspectRatioForCamera() {
- return getAppCompatOverrides().shouldOverrideMinAspectRatioForCamera();
- }
-
- /**
* Whether we should apply the force resize per-app override. When this override is applied it
* forces the packages it is applied to to be resizable. It won't change whether the app can be
* put into multi-windowing mode, but allow the app to resize without going into size-compat
@@ -242,16 +208,6 @@
.setRelaunchingAfterRequestedOrientationChanged(isRelaunching);
}
- /**
- * Whether activity "refresh" was requested but not finished in {@link #activityResumedLocked}.
- */
- boolean isRefreshRequested() {
- return mIsRefreshRequested;
- }
-
- void setIsRefreshRequested(boolean isRequested) {
- mIsRefreshRequested = isRequested;
- }
boolean isOverrideRespectRequestedOrientationEnabled() {
return getAppCompatOverrides().isOverrideRespectRequestedOrientationEnabled();
@@ -274,85 +230,6 @@
return getAppCompatOverrides().shouldUseDisplayLandscapeNaturalOrientation();
}
- boolean isOverrideOrientationOnlyForCameraEnabled() {
- return getAppCompatOverrides().isOverrideOrientationOnlyForCameraEnabled();
- }
-
- /**
- * Whether activity is eligible for activity "refresh" after camera compat force rotation
- * treatment. See {@link DisplayRotationCompatPolicy} for context.
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the camera compat treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override or by the app
- * developers with the component property.
- * </ul>
- */
- boolean shouldRefreshActivityForCameraCompat() {
- return getAppCompatOverrides().shouldRefreshActivityForCameraCompat();
- }
-
- /**
- * Whether activity should be "refreshed" after the camera compat force rotation treatment
- * using the "resumed -> paused -> resumed" cycle rather than the "resumed -> ... -> stopped
- * -> ... -> resumed" cycle. See {@link DisplayRotationCompatPolicy} for context.
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the camera compat treatment is enabled.
- * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle isn't disabled with the
- * component property by the app developers.
- * <li>Activity "refresh" via "resumed -> paused -> resumed" cycle is enabled by the device
- * manufacturer with override / by the app developers with the component property.
- * </ul>
- */
- boolean shouldRefreshActivityViaPauseForCameraCompat() {
- return getAppCompatOverrides().shouldRefreshActivityViaPauseForCameraCompat();
- }
-
- /**
- * Whether activity is eligible for camera compat force rotation treatment. See {@link
- * DisplayRotationCompatPolicy} for context.
- *
- * <p>This treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Flag gating the camera compat treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override or by the app
- * developers with the component property.
- * </ul>
- */
- boolean shouldForceRotateForCameraCompat() {
- return getAppCompatOverrides().shouldForceRotateForCameraCompat();
- }
-
- /**
- * Whether activity is eligible for camera compatibility free-form treatment.
- *
- * <p>The treatment is applied to a fixed-orientation camera activity in free-form windowing
- * mode. The treatment letterboxes or pillarboxes the activity to the expected orientation and
- * provides changes to the camera and display orientation signals to match those expected on a
- * portrait device in that orientation (for example, on a standard phone).
- *
- * <p>The treatment is enabled when the following conditions are met:
- * <ul>
- * <li>Property gating the camera compatibility free-form treatment is enabled.
- * <li>Activity isn't opted out by the device manufacturer with override.
- * </ul>
- */
- boolean shouldApplyFreeformTreatmentForCameraCompat() {
- return getAppCompatOverrides().shouldApplyFreeformTreatmentForCameraCompat();
- }
-
- @FreeformCameraCompatMode
- int getFreeformCameraCompatMode() {
- return mFreeformCameraCompatMode;
- }
-
- void setFreeformCameraCompatMode(@FreeformCameraCompatMode int freeformCameraCompatMode) {
- mFreeformCameraCompatMode = freeformCameraCompatMode;
- }
-
private boolean isCompatChangeEnabled(long overrideChangeId) {
return mActivityRecord.info.isChangeEnabled(overrideChangeId);
}
@@ -574,27 +451,10 @@
: getDefaultMinAspectRatio();
}
- void recomputeConfigurationForCameraCompatIfNeeded() {
- if (isOverrideOrientationOnlyForCameraEnabled()
- || isCameraCompatSplitScreenAspectRatioAllowed()
- || shouldOverrideMinAspectRatioForCamera()) {
- mActivityRecord.recomputeConfiguration();
- }
- }
-
boolean isLetterboxEducationEnabled() {
return mLetterboxConfiguration.getIsEducationEnabled();
}
- /**
- * Whether we use split screen aspect ratio for the activity when camera compat treatment
- * is active because the corresponding config is enabled and activity supports resizing.
- */
- boolean isCameraCompatSplitScreenAspectRatioAllowed() {
- return mLetterboxConfiguration.isCameraCompatSplitScreenAspectRatioEnabled()
- && !mActivityRecord.shouldCreateCompatDisplayInsets();
- }
-
private boolean shouldUseSplitScreenAspectRatio(@NonNull Configuration parentConfiguration) {
final boolean isBookMode = isDisplayFullScreenAndInPosture(/* isTabletop */ false);
final boolean isNotCenteredHorizontally = getHorizontalPositionMultiplier(
@@ -605,8 +465,9 @@
// Don't resize to split screen size when in book mode if letterbox position is centered
return (isBookMode && isNotCenteredHorizontally || isTabletopMode && isLandscape)
- || isCameraCompatSplitScreenAspectRatioAllowed()
- && getAppCompatOverrides().isCameraCompatTreatmentActive();
+ || mActivityRecord.mAppCompatController.getAppCompatCameraOverrides()
+ .isCameraCompatSplitScreenAspectRatioAllowed()
+ && getAppCompatOverrides().isCameraCompatTreatmentActive();
}
private float getDefaultMinAspectRatioForUnresizableApps() {
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index 0f9998c..0dadade 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -63,7 +63,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.IKeyguardDismissCallback;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.telephony.CellBroadcastUtils;
import com.android.internal.widget.LockPatternUtils;
diff --git a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
index 36c092b..1a895ea 100644
--- a/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/NonAppWindowAnimationAdapter.java
@@ -35,7 +35,7 @@
import android.view.SurfaceControl;
import android.view.WindowManager;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
index 4c797f8..3cf301c 100644
--- a/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
+++ b/services/core/java/com/android/server/wm/PhysicalDisplaySwitchTransitionLauncher.java
@@ -36,7 +36,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.wm.DeviceStateController.DeviceState;
public class PhysicalDisplaySwitchTransitionLauncher {
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index e07b72a..6f25280 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -80,7 +80,7 @@
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.am.ActivityManagerService;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 469cc64..c592caf 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -42,7 +42,7 @@
import android.util.Slog;
import android.view.IRecentsAnimationRunner;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 312c4be..6f94713 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -64,7 +64,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 63bbb31..a8edaeb 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -45,7 +45,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FastPrintWriter;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
diff --git a/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java b/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
index c22b07a..e4962bf 100644
--- a/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
+++ b/services/core/java/com/android/server/wm/RemoteDisplayChangeController.java
@@ -28,7 +28,7 @@
import android.window.WindowContainerTransaction;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.ArrayList;
import java.util.List;
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index d497d8c..243dbc7 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -24,7 +24,7 @@
import android.content.pm.ActivityInfo;
import android.os.Debug;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.ArrayList;
import java.util.function.Consumer;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6abd488..d1f1cab 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -141,7 +141,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ResolverActivity;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.LocalServices;
@@ -2158,6 +2158,12 @@
// Use Task#setBoundsUnchecked to skip checking windowing mode as the windowing mode
// will be updated later after this is collected in transition.
rootTask.setBoundsUnchecked(taskFragment.getBounds());
+ // The exit-PIP activity resumes early for seamless transition. In certain
+ // scenarios, this introduces unintended addition to recents. To address this,
+ // we mark the root task for automatic removal from recents. This ensures that
+ // after the pinned activity reparents to its original task, the root task is
+ // automatically removed from the recents list.
+ rootTask.autoRemoveRecents = true;
// Move the last recents animation transaction from original task to the new one.
if (task.mLastRecentsAnimationTransaction != null) {
diff --git a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
index 967f415..ad4faab 100644
--- a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
+++ b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
@@ -33,7 +33,7 @@
import android.window.IScreenRecordingCallback;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
import java.util.ArrayList;
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index e7bffdf..3eb3218 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -57,7 +57,7 @@
import com.android.internal.R;
import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.display.DisplayControl;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 4a0239b..9addce6 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -84,7 +84,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.logging.MetricsLoggerWrapper;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.LocalServices;
import com.android.server.wm.WindowManagerService.H;
import com.android.window.flags.Flags;
diff --git a/services/core/java/com/android/server/wm/SmoothDimmer.java b/services/core/java/com/android/server/wm/SmoothDimmer.java
index b5d94a2..2b4d901 100644
--- a/services/core/java/com/android/server/wm/SmoothDimmer.java
+++ b/services/core/java/com/android/server/wm/SmoothDimmer.java
@@ -26,7 +26,7 @@
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
class SmoothDimmer extends Dimmer {
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index c632714..9cfd396 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -33,7 +33,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
import java.io.StringWriter;
diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java
index 0c36d27..34abf23 100644
--- a/services/core/java/com/android/server/wm/SurfaceFreezer.java
+++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java
@@ -31,7 +31,7 @@
import android.window.ScreenCapture;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
/**
* This class handles "freezing" of an Animatable. The Animatable in question should implement
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f9c53aa..f0b0e91 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -181,7 +181,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
@@ -3522,7 +3522,8 @@
appCompatTaskInfo.topActivityBoundsLetterboxed = top != null && top.areBoundsLetterboxed();
appCompatTaskInfo.cameraCompatTaskInfo.freeformCameraCompatMode = top == null
? CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE
- : top.mLetterboxUiController.getFreeformCameraCompatMode();
+ : top.mAppCompatController.getAppCompatCameraOverrides()
+ .getFreeformCameraCompatMode();
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index eff8315..eaf3012 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -52,7 +52,7 @@
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 3cd071b..9b2c022 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -106,7 +106,7 @@
import android.window.TaskFragmentOrganizerToken;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.am.HostingRecord;
import com.android.server.pm.pkg.AndroidPackage;
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 26315f9..b6b6cf2 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -59,7 +59,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import java.lang.annotation.Retention;
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index b24d53b..6e36d427 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -57,7 +57,7 @@
import android.window.WindowContainerToken;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 9b3fb6b..972dd2e 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -59,7 +59,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.TaskResizingAlgorithm;
import com.android.internal.policy.TaskResizingAlgorithm.CtrlType;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.concurrent.CompletableFuture;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index e698a3d..35a7702 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -106,7 +106,7 @@
import com.android.internal.graphics.ColorUtils;
import com.android.internal.policy.TransitionAnimation;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 0812323..f4ff404 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -53,7 +53,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.FgThread;
import com.android.window.flags.Flags;
diff --git a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
index fa2d9bf..c0dc424 100644
--- a/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
+++ b/services/core/java/com/android/server/wm/TrustedPresentationListenerController.java
@@ -40,7 +40,7 @@
import android.window.TrustedPresentationThresholds;
import android.window.WindowInfosListener;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.wm.utils.RegionUtils;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index 4a5a20e..fffe692 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -27,7 +27,7 @@
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.wm.SurfaceAnimator.AnimationType;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 43f7ecc..3b5a605 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -57,7 +57,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.wallpaper.WallpaperCropper.WallpaperCropUtils;
import com.android.window.flags.Flags;
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index b7f8505..31156de 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -31,7 +31,7 @@
import android.os.RemoteException;
import android.util.SparseArray;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import java.util.function.Consumer;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 8afcf0e..03342d3 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -34,7 +34,7 @@
import android.view.Choreographer;
import android.view.SurfaceControl;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 1f31af6..325ef0d 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -111,7 +111,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.wm.SurfaceAnimator.Animatable;
import com.android.server.wm.SurfaceAnimator.AnimationType;
diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
index b000a98..57fc4c7 100644
--- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
+++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
@@ -39,7 +39,7 @@
import android.view.SurfaceControl.Transaction;
import android.view.animation.Animation;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.wm.SurfaceAnimator.Animatable;
import com.android.server.wm.SurfaceAnimator.AnimationType;
diff --git a/services/core/java/com/android/server/wm/WindowContextListenerController.java b/services/core/java/com/android/server/wm/WindowContextListenerController.java
index 21f251f..cd785e5 100644
--- a/services/core/java/com/android/server/wm/WindowContextListenerController.java
+++ b/services/core/java/com/android/server/wm/WindowContextListenerController.java
@@ -39,7 +39,7 @@
import android.window.WindowContext;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.util.Objects;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5215609..57b8040 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -335,7 +335,7 @@
import com.android.internal.policy.KeyInterceptionInfo;
import com.android.internal.protolog.LegacyProtoLogImpl;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.FrameworkStatsLog;
@@ -3743,6 +3743,8 @@
null /* trigger */, null /* remote */, null /* disp */);
}
mCurrentUserId = newUserId;
+ mDisplayWindowSettingsProvider.setOverrideSettingsForUser(newUserId);
+ mDisplayWindowSettingsProvider.removeStaleDisplaySettings(mRoot);
mPolicy.setCurrentUserLw(newUserId);
mKeyguardDisableHandler.setCurrentUser(newUserId);
@@ -5479,6 +5481,9 @@
// DisplayWindowSettings are applied. In addition, wide-color/hdr/isTouchDevice also
// affect the Configuration.
mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);
+ // Per-user display settings may leave outdated settings after user switches, especially
+ // during reboots starting with the default user without setCurrentUser called.
+ mDisplayWindowSettingsProvider.removeStaleDisplaySettings(mRoot);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 1f06bfa..6febe80 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -51,7 +51,7 @@
import com.android.internal.protolog.LegacyProtoLogImpl;
import com.android.internal.protolog.PerfettoProtoLogImpl;
import com.android.internal.protolog.common.IProtoLog;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.IoThread;
import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
import com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index d26df7a..de58457 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -124,7 +124,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.pm.LauncherAppsService.LauncherAppsServiceInternal;
@@ -1105,6 +1105,7 @@
break;
}
if (activity.isVisible() || activity.isVisibleRequested()) {
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
// Prevent the transition from being executed too early if the activity is
// visible.
activity.finishIfPossible("finish-activity-op", false /* oomAdj */);
@@ -1122,6 +1123,7 @@
launchOpts.remove(WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID);
final SafeActivityOptions safeOptions =
SafeActivityOptions.fromBundle(launchOpts, caller.mPid, caller.mUid);
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
waitAsyncStart(() -> mService.mTaskSupervisor.startActivityFromRecents(
caller.mPid, caller.mUid, taskId, safeOptions));
break;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index b878072..60d3e78 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -82,7 +82,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.Watchdog;
import com.android.server.grammaticalinflection.GrammaticalInflectionManagerInternal;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d845968..fec1175 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -250,7 +250,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.KeyInterceptionInfo;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.policy.WindowManagerPolicy;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 9ecd492..397a6357 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -62,7 +62,7 @@
import android.view.animation.AnimationUtils;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.window.flags.Flags;
import com.android.server.policy.WindowManagerPolicy;
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 4456a94..d9766e0 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -36,7 +36,7 @@
import android.view.SurfaceControl;
import android.view.WindowContentFrameStats;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 4dca23b..11ef2cd 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -47,7 +47,7 @@
import android.view.WindowManager.LayoutParams.WindowType;
import android.window.WindowContext;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index b0e71bd..ba5323e 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -37,7 +37,7 @@
import com.android.internal.protolog.LegacyProtoLogImpl;
import com.android.internal.protolog.common.IProtoLog;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.TraceBuffer;
import java.io.File;
diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
index c558aae..7ed23cd 100644
--- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt
@@ -230,18 +230,7 @@
}
val isSoftRestricted =
if (permission.isSoftRestricted && !isExempt) {
- val targetSdkVersion =
- reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT) {
- targetSdkVersion,
- packageState ->
- if (permissionName in packageState.androidPackage!!.requestedPermissions) {
- targetSdkVersion.coerceAtMost(
- packageState.androidPackage!!.targetSdkVersion
- )
- } else {
- targetSdkVersion
- }
- }
+ val targetSdkVersion = getAppIdTargetSdkVersion(appId, permissionName)
!anyPackageInAppId(appId) {
permissionName in it.androidPackage!!.requestedPermissions &&
isSoftRestrictedPermissionExemptForPackage(
@@ -718,18 +707,8 @@
// If the app is updated, and has scoped storage permissions, then it is possible that the
// app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
- val oldTargetSdkVersion =
- reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, oldState) {
- targetSdkVersion,
- packageState ->
- targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
- }
- val newTargetSdkVersion =
- reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, newState) {
- targetSdkVersion,
- packageState ->
- targetSdkVersion.coerceAtMost(packageState.androidPackage!!.targetSdkVersion)
- }
+ val oldTargetSdkVersion = getAppIdTargetSdkVersion(appId, null, oldState)
+ val newTargetSdkVersion = getAppIdTargetSdkVersion(appId, null, newState)
@Suppress("ConvertTwoComparisonsToRangeCheck")
val isTargetSdkVersionDowngraded =
oldTargetSdkVersion >= Build.VERSION_CODES.Q &&
@@ -1115,10 +1094,9 @@
}
private fun MutateStateScope.inheritImplicitPermissionStates(appId: Int, userId: Int) {
- var targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT
+ val targetSdkVersion = getAppIdTargetSdkVersion(appId, null)
val implicitPermissions = MutableIndexedSet<String>()
forEachPackageInAppId(appId) {
- targetSdkVersion = targetSdkVersion.coerceAtMost(it.androidPackage!!.targetSdkVersion)
implicitPermissions += it.androidPackage!!.implicitPermissions
}
implicitPermissions.forEachIndexed implicitPermissions@{ _, implicitPermissionName ->
@@ -1418,6 +1396,22 @@
else -> false
}
+ private fun MutateStateScope.getAppIdTargetSdkVersion(
+ appId: Int,
+ permissionName: String?,
+ state: AccessState = newState
+ ): Int =
+ reducePackageInAppId(appId, Build.VERSION_CODES.CUR_DEVELOPMENT, state) {
+ targetSdkVersion,
+ packageState ->
+ val androidPackage = packageState.androidPackage!!
+ if (permissionName == null || permissionName in androidPackage.requestedPermissions) {
+ targetSdkVersion.coerceAtMost(androidPackage.targetSdkVersion)
+ } else {
+ targetSdkVersion
+ }
+ }
+
private inline fun MutateStateScope.anyPackageInAppId(
appId: Int,
state: AccessState = newState,
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
index 33ea9b4..9e46f2f 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
@@ -37,6 +37,7 @@
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import static java.util.Objects.requireNonNull;
@@ -134,8 +135,10 @@
@Test
public void testApplyImeVisibility_hideImeExplicit() throws Exception {
- mInputMethodManagerService.mImeWindowVis = IME_ACTIVE;
synchronized (ImfLock.class) {
+ final var bindingController =
+ mInputMethodManagerService.getInputMethodBindingController(mUserId);
+ when(bindingController.getImeWindowVis()).thenReturn(IME_ACTIVE);
mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
STATE_HIDE_IME_EXPLICIT, eq(SoftInputShowHideReason.NOT_SET), mUserId);
}
@@ -144,8 +147,10 @@
@Test
public void testApplyImeVisibility_hideNotAlways() throws Exception {
- mInputMethodManagerService.mImeWindowVis = IME_ACTIVE;
synchronized (ImfLock.class) {
+ final var bindingController =
+ mInputMethodManagerService.getInputMethodBindingController(mUserId);
+ when(bindingController.getImeWindowVis()).thenReturn(IME_ACTIVE);
mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
STATE_HIDE_IME_NOT_ALWAYS, eq(SoftInputShowHideReason.NOT_SET), mUserId);
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 7b8b712..d070aaa 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1700,10 +1700,12 @@
verify(mDisplayOffloadSession, never()).cancelBlockScreenOn();
}
- @RequiresFlagsEnabled(Flags.FLAG_OFFLOAD_SESSION_CANCEL_BLOCK_SCREEN_ON)
@Test
public void testOffloadBlocker_turnON_thenOFF_cancelBlockScreenOnNotCalledIfUnblocked() {
// Set up.
+ when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
+ when(mDisplayManagerFlagsMock.isOffloadSessionCancelBlockScreenOnEnabled())
+ .thenReturn(true);
int initState = Display.STATE_OFF;
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
@@ -1737,10 +1739,12 @@
verify(mDisplayOffloadSession, never()).cancelBlockScreenOn();
}
- @RequiresFlagsEnabled(Flags.FLAG_OFFLOAD_SESSION_CANCEL_BLOCK_SCREEN_ON)
@Test
public void testOffloadBlocker_turnON_thenOFF_cancelBlockScreenOn() {
// Set up.
+ when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
+ when(mDisplayManagerFlagsMock.isOffloadSessionCancelBlockScreenOnEnabled())
+ .thenReturn(true);
int initState = Display.STATE_OFF;
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
index 123f0ed..ca30551 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
@@ -28,6 +28,7 @@
import static android.view.accessibility.AccessibilityManager.STATE_FLAG_HIGH_TEXT_CONTRAST_ENABLED;
import static android.view.accessibility.AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.QUICK_SETTINGS;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE;
@@ -163,6 +164,7 @@
mUserState.mTouchExplorationGrantedServices.add(COMPONENT_NAME);
mUserState.updateShortcutTargetsLocked(Set.of(COMPONENT_NAME.flattenToString()), HARDWARE);
mUserState.updateShortcutTargetsLocked(Set.of(COMPONENT_NAME.flattenToString()), SOFTWARE);
+ mUserState.updateShortcutTargetsLocked(Set.of(COMPONENT_NAME.flattenToString()), GESTURE);
mUserState.setTargetAssignedToAccessibilityButton(COMPONENT_NAME.flattenToString());
mUserState.setTouchExplorationEnabledLocked(true);
mUserState.setMagnificationSingleFingerTripleTapEnabledLocked(true);
@@ -186,6 +188,7 @@
assertTrue(mUserState.mTouchExplorationGrantedServices.isEmpty());
assertTrue(mUserState.getShortcutTargetsLocked(HARDWARE).isEmpty());
assertTrue(mUserState.getShortcutTargetsLocked(SOFTWARE).isEmpty());
+ assertTrue(mUserState.getShortcutTargetsLocked(GESTURE).isEmpty());
assertNull(mUserState.getTargetAssignedToAccessibilityButton());
assertFalse(mUserState.isTouchExplorationEnabledLocked());
assertFalse(mUserState.isMagnificationSingleFingerTripleTapEnabledLocked());
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index 36a5cda..9cd3186 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -393,18 +393,6 @@
testAuthenticate_throwsSecurityException(promptInfo);
}
- @Test
- public void testCanAuthenticate_throwsWhenUsingAdvancedApis() {
- mAuthService = new AuthService(mContext, mInjector);
- mAuthService.onStart();
-
- assertThrows(SecurityException.class, () -> {
- mAuthService.mImpl.canAuthenticate(TEST_OP_PACKAGE_NAME, 1 /* userId */,
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
- waitForIdle();
- });
- }
-
private void testAuthenticate_throwsSecurityException(PromptInfo promptInfo) {
mAuthService = new AuthService(mContext, mInjector);
mAuthService.onStart();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 2a4b797..21364b8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -2012,38 +2012,94 @@
}
@Test
- public void handleStandby_fromActiveSource_standby() {
- mPowerManager.setInteractive(true);
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ public void handleStandby_fromActiveSource_previousActiveSourceSet_standby() {
+ mHdmiCecLocalDeviceTv = new MockTvDevice(mHdmiControlService);
+ HdmiCecMessage activeSourceFromPlayback =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_1, 0x1000);
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
+ ADDR_TV);
mTestLooper.dispatchAll();
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isFalse();
+ mPowerManager.setInteractive(true);
+ mTestLooper.dispatchAll();
+
+ mHdmiCecLocalDeviceTv.dispatchMessage(activeSourceFromPlayback);
mHdmiControlService.setActiveSource(ADDR_PLAYBACK_1, 0x1000,
"HdmiCecLocalDeviceTvTest");
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
- ADDR_TV);
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isTrue();
assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
.isEqualTo(Constants.HANDLED);
mTestLooper.dispatchAll();
assertThat(mPowerManager.isInteractive()).isFalse();
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isFalse();
}
@Test
- public void handleStandby_fromNonActiveSource_noStandby() {
+ public void handleStandby_fromNonActiveSource_previousActiveSourceSet_noStandby() {
+ HdmiCecMessage activeSourceFromPlayback =
+ HdmiCecMessageBuilder.buildActiveSource(ADDR_PLAYBACK_2, 0x2000);
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
+ ADDR_TV);
+ mHdmiCecLocalDeviceTv = new MockTvDevice(mHdmiControlService);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isFalse();
mPowerManager.setInteractive(true);
- mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+
+ mHdmiCecLocalDeviceTv.dispatchMessage(activeSourceFromPlayback);
mHdmiControlService.setActiveSource(ADDR_PLAYBACK_2, 0x2000,
"HdmiCecLocalDeviceTvTest");
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
- ADDR_TV);
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isTrue();
assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
.isEqualTo(Constants.HANDLED);
mTestLooper.dispatchAll();
assertThat(mPowerManager.isInteractive()).isTrue();
}
+
+
+ @Test
+ public void handleStandby_fromNonActiveSource_previousActiveSourceNotSet_Standby() {
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
+ ADDR_TV);
+ mHdmiCecLocalDeviceTv = new MockTvDevice(mHdmiControlService);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isFalse();
+ mPowerManager.setInteractive(true);
+
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isFalse();
+ assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
+ .isEqualTo(Constants.HANDLED);
+ mTestLooper.dispatchAll();
+
+ assertThat(mPowerManager.isInteractive()).isFalse();
+ assertThat(mHdmiCecLocalDeviceTv.getWasActiveSourceSetToConnectedDevice())
+ .isFalse();
+ }
+
+ protected static class MockTvDevice extends HdmiCecLocalDeviceTv {
+ MockTvDevice(HdmiControlService service) {
+ super(service);
+ }
+
+ @Override
+ protected int handleActiveSource(HdmiCecMessage message) {
+ setWasActiveSourceSetToConnectedDevice(true);
+ return super.handleActiveSource(message);
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 37065fd..02d3b59 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -1424,6 +1424,39 @@
@MediumTest
@Test
+ public void testSerialNumberAfterUserRemoval() {
+ final UserInfo user = mUserManager.createUser("Test User", 0);
+ assertThat(user).isNotNull();
+
+ final int userId = user.id;
+ assertThat(mUserManager.getUserSerialNumber(userId))
+ .isEqualTo(user.serialNumber);
+ mUsersToRemove.add(userId);
+ removeUser(userId);
+ int serialNumber = mUserManager.getUserSerialNumber(userId);
+ int timeout = REMOVE_USER_TIMEOUT_SECONDS * 5; // called every 200ms
+
+ // Wait for the user to be removed from memory
+ while(serialNumber > 0 && timeout > 0){
+ sleep(200);
+ timeout--;
+ serialNumber = mUserManager.getUserSerialNumber(userId);
+ }
+ assertThat(serialNumber).isEqualTo(-1);
+ }
+
+
+ private void sleep(long millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ @MediumTest
+ @Test
public void testMaxUsers() {
int N = UserManager.getMaxSupportedUsers();
int count = mUserManager.getUsers().size();
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index b292294..6ba2c70 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -28,7 +28,7 @@
],
tools: ["protologtool"],
cmd: "$(location protologtool) transform-protolog-calls " +
- "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
"--loggroups-jar $(location :protolog-groups) " +
// Used for the ProtoLogIntegrationTest, where don't test decoding or writing to file
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java
index 12ab3e1..a3252f8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRefresherTests.java
@@ -103,8 +103,8 @@
@Test
public void testShouldRefreshActivity_refreshDisabledForActivity() throws Exception {
configureActivityAndDisplay();
- when(mActivity.mLetterboxUiController.shouldRefreshActivityForCameraCompat())
- .thenReturn(false);
+ when(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldRefreshActivityForCameraCompat()).thenReturn(false);
mActivityRefresher.addEvaluator(mEvaluatorTrue);
mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig);
@@ -160,8 +160,9 @@
throws Exception {
configureActivityAndDisplay();
mActivityRefresher.addEvaluator(mEvaluatorTrue);
- doReturn(true).when(mActivity.mLetterboxUiController)
- .shouldRefreshActivityViaPauseForCameraCompat();
+ doReturn(true)
+ .when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
+ .shouldRefreshActivityViaPauseForCameraCompat();
mActivityRefresher.onActivityConfigurationChanging(mActivity, mNewConfig, mOldConfig);
@@ -172,8 +173,9 @@
public void testOnActivityRefreshed_setIsRefreshRequestedToFalse() throws Exception {
configureActivityAndDisplay();
mActivityRefresher.addEvaluator(mEvaluatorTrue);
- doReturn(true).when(mActivity.mLetterboxUiController)
- .shouldRefreshActivityViaPauseForCameraCompat();
+ doReturn(true)
+ .when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
+ .shouldRefreshActivityViaPauseForCameraCompat();
mActivityRefresher.onActivityRefreshed(mActivity);
@@ -186,8 +188,8 @@
private void assertActivityRefreshRequested(boolean refreshRequested,
boolean cycleThroughStop) throws Exception {
- verify(mActivity.mLetterboxUiController, times(refreshRequested ? 1 : 0))
- .setIsRefreshRequested(true);
+ verify(mActivity.mAppCompatController.getAppCompatCameraOverrides(),
+ times(refreshRequested ? 1 : 0)).setIsRefreshRequested(true);
final RefreshCallbackItem refreshCallbackItem = RefreshCallbackItem.obtain(mActivity.token,
cycleThroughStop ? ON_STOP : ON_PAUSE);
@@ -211,9 +213,9 @@
.getTopMostActivity();
spyOn(mActivity.mLetterboxUiController);
- doReturn(true).when(
- mActivity.mLetterboxUiController).shouldRefreshActivityForCameraCompat();
-
+ spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides());
doReturn(true).when(mActivity).inFreeformWindowingMode();
+ doReturn(true).when(mActivity.mAppCompatController
+ .getAppCompatCameraOverrides()).shouldRefreshActivityForCameraCompat();
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
index 5f2853a..467050e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
@@ -149,6 +149,10 @@
.mLetterboxUiController).shouldApplyUserMinAspectRatioOverride();
}
+ void setShouldCreateCompatDisplayInsets(boolean enabled) {
+ doReturn(enabled).when(mActivityStack.top()).shouldCreateCompatDisplayInsets();
+ }
+
void setShouldApplyUserFullscreenOverride(boolean enabled) {
doReturn(enabled).when(mActivityStack.top()
.mLetterboxUiController).shouldApplyUserFullscreenOverride();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
new file mode 100644
index 0000000..9263b4f
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
@@ -0,0 +1,320 @@
+/*
+ * 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_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
+import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
+import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
+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 com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM;
+
+import android.compat.testing.PlatformCompatChangeRule;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.annotation.NonNull;
+
+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 org.testng.Assert;
+
+import java.util.function.Consumer;
+
+/**
+ * Test class for {@link AppCompatCameraOverrides}.
+ * <p>
+ * Build/Install/Run:
+ * atest WmTests:AppCompatCameraOverridesTest
+ */
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class AppCompatCameraOverridesTest extends WindowTestsBase {
+
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
+ @Test
+ public void testShouldRefreshActivityForCameraCompat_flagIsDisabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(false);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
+ public void testShouldRefreshActivityForCameraCompat_overrideEnabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
+ public void testShouldRefreshActivityForCameraCompat_propertyIsTrueAndOverride_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().enable(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityForCameraCompat(false);
+ });
+ }
+
+ @Test
+ public void testShouldRefreshActivityForCameraCompat_propertyIsFalse_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().disable(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityForCameraCompat(false);
+ });
+ }
+
+ @Test
+ public void testShouldRefreshActivityForCameraCompat_propertyIsTrue_returnsTrue() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().enable(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityForCameraCompat(true);
+ });
+ }
+
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
+ public void testShouldRefreshActivityViaPauseForCameraCompat_flagIsDisabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(false);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityViaPauseForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
+ public void testShouldRefreshActivityViaPauseForCameraCompat_overrideEnabled_returnsTrue() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityViaPauseForCameraCompat(true);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
+ public void testShouldRefreshActivityViaPauseForCameraCompat_propertyFalseAndOverrideFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().disable(PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityViaPauseForCameraCompat(false);
+ });
+ }
+
+ @Test
+ public void testShouldRefreshActivityViaPauseForCameraCompat_propertyIsTrue_returnsTrue() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().enable(PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldRefreshActivityViaPauseForCameraCompat(true);
+ });
+ }
+
+ @Test
+ public void testShouldForceRotateForCameraCompat_flagIsDisabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(false);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldForceRotateForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION})
+ public void testShouldForceRotateForCameraCompat_overrideEnabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldForceRotateForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION})
+ public void testShouldForceRotateForCameraCompat_propertyIsTrueAndOverride_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().enable(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldForceRotateForCameraCompat(false);
+ });
+ }
+
+ @Test
+ public void testShouldForceRotateForCameraCompat_propertyIsFalse_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().disable(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldForceRotateForCameraCompat(false);
+ });
+ }
+
+ @Test
+ public void testShouldForceRotateForCameraCompat_propertyIsTrue_returnsTrue() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatTreatment(true);
+ robot.prop().enable(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION);
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldForceRotateForCameraCompat(true);
+ });
+ }
+
+ @Test
+ @DisableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+ public void testShouldApplyCameraCompatFreeformTreatment_flagIsDisabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldApplyFreeformTreatmentForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
+ @EnableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+ public void testShouldApplyCameraCompatFreeformTreatment_overrideEnabled_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldApplyFreeformTreatmentForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
+ @EnableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+ public void testShouldApplyCameraCompatFreeformTreatment_disabledByOverride_returnsFalse() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldApplyFreeformTreatmentForCameraCompat(false);
+ });
+ }
+
+ @Test
+ @EnableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+ public void testShouldApplyCameraCompatFreeformTreatment_notDisabledByOverride_returnsTrue() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponentInNewTask();
+
+ robot.checkShouldApplyFreeformTreatmentForCameraCompat(true);
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA,
+ OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
+ public void testShouldRecomputeConfigurationForCameraCompat() {
+ runTestScenario((robot) -> {
+ robot.conf().enableCameraCompatSplitScreenAspectRatio(true);
+ robot.activity().createActivityWithComponentInNewTask();
+ robot.activateCamera(true);
+ robot.activity().setShouldCreateCompatDisplayInsets(false);
+
+ robot.checkShouldApplyFreeformTreatmentForCameraCompat(true);
+ });
+ }
+
+ /**
+ * Runs a test scenario providing a Robot.
+ */
+ void runTestScenario(@NonNull Consumer<CameraOverridesRobotTest> consumer) {
+ spyOn(mWm.mLetterboxConfiguration);
+ final CameraOverridesRobotTest robot = new CameraOverridesRobotTest(mWm, mAtm, mSupervisor);
+ consumer.accept(robot);
+ }
+
+ private static class CameraOverridesRobotTest extends AppCompatRobotBase {
+
+ CameraOverridesRobotTest(@NonNull WindowManagerService wm,
+ @NonNull ActivityTaskManagerService atm,
+ @NonNull ActivityTaskSupervisor supervisor) {
+ super(wm, atm, supervisor);
+ }
+
+ void activateCamera(boolean isCameraActive) {
+ doReturn(isCameraActive).when(activity().top()).isCameraActive();
+ }
+
+ void checkShouldRefreshActivityForCameraCompat(boolean expected) {
+ Assert.assertEquals(getAppCompatCameraOverrides()
+ .shouldRefreshActivityForCameraCompat(), expected);
+ }
+
+ void checkShouldRefreshActivityViaPauseForCameraCompat(boolean expected) {
+ Assert.assertEquals(getAppCompatCameraOverrides()
+ .shouldRefreshActivityViaPauseForCameraCompat(), expected);
+ }
+
+ void checkShouldForceRotateForCameraCompat(boolean expected) {
+ Assert.assertEquals(getAppCompatCameraOverrides()
+ .shouldForceRotateForCameraCompat(), expected);
+ }
+
+ void checkShouldApplyFreeformTreatmentForCameraCompat(boolean expected) {
+ Assert.assertEquals(getAppCompatCameraOverrides()
+ .shouldApplyFreeformTreatmentForCameraCompat(), expected);
+ }
+
+ private AppCompatCameraOverrides getAppCompatCameraOverrides() {
+ return activity().top().mAppCompatController.getAppCompatCameraOverrides();
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java
new file mode 100644
index 0000000..4116313
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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_ONLY_FOR_CAMERA;
+import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+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 AppCompatCameraPolicy}.
+ * <p>
+ * Build/Install/Run:
+ * atest WmTests:AppCompatCameraPolicyTest
+ */
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class AppCompatCameraPolicyTest extends WindowTestsBase {
+
+ @Rule
+ public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
+ @Test
+ @DisableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
+ public void testRecomputeConfigurationForCameraCompatIfNeeded_allDisabledNoRecompute() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponent();
+ robot.conf().enableCameraCompatSplitScreenAspectRatio(false);
+ robot.activateCamera(/* isCameraActive */ false);
+
+ robot.recomputeConfigurationForCameraCompatIfNeeded();
+ robot.checkRecomputeConfigurationInvoked(/* invoked */ false);
+
+ });
+ }
+
+ @Test
+ @EnableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
+ public void testRecomputeConfigurationForCameraCompatIfNeeded_cameraEnabledRecompute() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponent();
+ robot.conf().enableCameraCompatSplitScreenAspectRatio(false);
+ robot.activateCamera(/* isCameraActive */ false);
+
+ robot.recomputeConfigurationForCameraCompatIfNeeded();
+ robot.checkRecomputeConfigurationInvoked(/* invoked */ true);
+ });
+ }
+
+ @Test
+ @DisableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
+ public void testRecomputeConfigurationForCameraSplitScreenCompatIfNeeded_recompute() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponent();
+ robot.conf().enableCameraCompatSplitScreenAspectRatio(true);
+ robot.activateCamera(/* isCameraActive */ false);
+
+ robot.recomputeConfigurationForCameraCompatIfNeeded();
+ robot.checkRecomputeConfigurationInvoked(/* invoked */ true);
+ });
+ }
+
+ @Test
+ @DisableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
+ @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
+ public void testRecomputeConfigurationForCameraSplitScreenCompatIfNeededWithCamera_recompute() {
+ runTestScenario((robot) -> {
+ robot.activity().createActivityWithComponent();
+ robot.conf().enableCameraCompatSplitScreenAspectRatio(false);
+ robot.activateCamera(/* isCameraActive */ true);
+
+ robot.recomputeConfigurationForCameraCompatIfNeeded();
+ robot.checkRecomputeConfigurationInvoked(/* invoked */ true);
+ });
+ }
+
+ void runTestScenario(@NonNull Consumer<CameraPolicyRobotTest> consumer) {
+ spyOn(mWm.mLetterboxConfiguration);
+ final CameraPolicyRobotTest robot = new CameraPolicyRobotTest(mWm, mAtm, mSupervisor);
+ consumer.accept(robot);
+ }
+
+ private static class CameraPolicyRobotTest extends AppCompatRobotBase {
+
+ private final WindowManagerService mWm;
+
+ CameraPolicyRobotTest(@NonNull WindowManagerService wm,
+ @NonNull ActivityTaskManagerService atm,
+ @NonNull ActivityTaskSupervisor supervisor) {
+ super(wm, atm, supervisor);
+ mWm = wm;
+ spyOn(mWm);
+ }
+
+ void activateCamera(boolean isCameraActive) {
+ doReturn(isCameraActive).when(activity().top()).isCameraActive();
+ }
+
+ void recomputeConfigurationForCameraCompatIfNeeded() {
+ getAppCompatCameraPolicy().recomputeConfigurationForCameraCompatIfNeeded();
+ }
+
+ void checkRecomputeConfigurationInvoked(boolean invoked) {
+ if (invoked) {
+ verify(activity().top()).recomputeConfiguration();
+ } else {
+ verify(activity().top(), never()).recomputeConfiguration();
+ }
+ }
+
+ private AppCompatCameraPolicy getAppCompatCameraPolicy() {
+ return activity().top().mAppCompatController.getAppCompatCameraPolicy();
+ }
+ }
+
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxConfigurationRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxConfigurationRobot.java
index 2ef77f6..e1da913 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxConfigurationRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxConfigurationRobot.java
@@ -61,4 +61,11 @@
void enableUserAppAspectRatioSettings(boolean enabled) {
doReturn(enabled).when(mLetterboxConfiguration).isUserAppAspectRatioSettingsEnabled();
}
+
+ void enableCameraCompatSplitScreenAspectRatio(boolean enabled) {
+ doReturn(enabled).when(mLetterboxConfiguration)
+ .isCameraCompatSplitScreenAspectRatioEnabled();
+ }
+
+
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
index b3f1502..564c29f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/CameraCompatFreeformPolicyTests.java
@@ -245,8 +245,8 @@
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(false).when(
- mActivity.mLetterboxUiController).shouldRefreshActivityForCameraCompat();
+ doReturn(false).when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
+ .shouldRefreshActivityForCameraCompat();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
callOnActivityConfigurationChanging(mActivity);
@@ -271,7 +271,7 @@
public void testOnActivityConfigurationChanging_cycleThroughStopDisabledForApp()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(true).when(mActivity.mLetterboxUiController)
+ doReturn(true).when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
.shouldRefreshActivityViaPauseForCameraCompat();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
@@ -305,6 +305,7 @@
.build();
spyOn(mActivity.mLetterboxUiController);
+ spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides());
spyOn(mActivity.info);
doReturn(mActivity).when(mDisplayContent).topRunningActivity(anyBoolean());
@@ -315,12 +316,14 @@
private void assertInCameraCompatMode() {
assertNotEquals(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE,
- mActivity.mLetterboxUiController.getFreeformCameraCompatMode());
+ mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .getFreeformCameraCompatMode());
}
private void assertNotInCameraCompatMode() {
assertEquals(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_NONE,
- mActivity.mLetterboxUiController.getFreeformCameraCompatMode());
+ mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .getFreeformCameraCompatMode());
}
private void assertActivityRefreshRequested(boolean refreshRequested) throws Exception {
@@ -329,8 +332,8 @@
private void assertActivityRefreshRequested(boolean refreshRequested,
boolean cycleThroughStop) throws Exception {
- verify(mActivity.mLetterboxUiController, times(refreshRequested ? 1 : 0))
- .setIsRefreshRequested(true);
+ verify(mActivity.mAppCompatController.getAppCompatCameraOverrides(),
+ times(refreshRequested ? 1 : 0)).setIsRefreshRequested(true);
final RefreshCallbackItem refreshCallbackItem = RefreshCallbackItem.obtain(mActivity.token,
cycleThroughStop ? ON_STOP : ON_PAUSE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
index c65371f..d7814ac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationCompatPolicyTests.java
@@ -266,7 +266,7 @@
public void testTreatmentDisabledPerApp_noForceRotationOrRefresh()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(false).when(mActivity.mLetterboxUiController)
+ doReturn(false).when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
.shouldForceRotateForCameraCompat();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
@@ -468,8 +468,8 @@
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(false).when(
- mActivity.mLetterboxUiController).shouldRefreshActivityForCameraCompat();
+ doReturn(false).when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
+ .shouldRefreshActivityForCameraCompat();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
callOnActivityConfigurationChanging(mActivity, /* isDisplayRotationChanging */ true);
@@ -494,8 +494,9 @@
public void testOnActivityConfigurationChanging_displayRotationNotChanging_noRefresh()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(false).when(mActivity.mLetterboxUiController)
- .isCameraCompatSplitScreenAspectRatioAllowed();
+ doReturn(false).when(mActivity
+ .mAppCompatController.getAppCompatCameraOverrides())
+ .isCameraCompatSplitScreenAspectRatioAllowed();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
callOnActivityConfigurationChanging(mActivity, /* isDisplayRotationChanging */ false);
@@ -507,7 +508,7 @@
public void testOnActivityConfigurationChanging_splitScreenAspectRatioAllowed_refresh()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(true).when(mActivity.mLetterboxUiController)
+ doReturn(true).when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
.isCameraCompatSplitScreenAspectRatioAllowed();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
@@ -533,7 +534,7 @@
public void testOnActivityConfigurationChanging_cycleThroughStopDisabledForApp()
throws Exception {
configureActivity(SCREEN_ORIENTATION_PORTRAIT);
- doReturn(true).when(mActivity.mLetterboxUiController)
+ doReturn(true).when(mActivity.mAppCompatController.getAppCompatCameraOverrides())
.shouldRefreshActivityViaPauseForCameraCompat();
mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);
@@ -597,6 +598,7 @@
spyOn(mActivity.mAtmService.getLifecycleManager());
spyOn(mActivity.mLetterboxUiController);
+ spyOn(mActivity.mAppCompatController.getAppCompatCameraOverrides());
doReturn(mActivity).when(mDisplayContent).topRunningActivity(anyBoolean());
doReturn(naturalOrientation).when(mDisplayContent).getNaturalOrientation();
@@ -608,8 +610,8 @@
private void assertActivityRefreshRequested(boolean refreshRequested,
boolean cycleThroughStop) throws Exception {
- verify(mActivity.mLetterboxUiController, times(refreshRequested ? 1 : 0))
- .setIsRefreshRequested(true);
+ verify(mActivity.mAppCompatController.getAppCompatCameraOverrides(),
+ times(refreshRequested ? 1 : 0)).setIsRefreshRequested(true);
final RefreshCallbackItem refreshCallbackItem = RefreshCallbackItem.obtain(mActivity.token,
cycleThroughStop ? ON_STOP : ON_PAUSE);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index 7d9fdd5..3fcf304 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -24,9 +24,12 @@
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import static org.testng.Assert.assertFalse;
import android.annotation.Nullable;
@@ -55,6 +58,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
+import java.util.function.Consumer;
/**
* Tests for the {@link DisplayWindowSettingsProvider} class.
@@ -128,9 +132,8 @@
// Update settings with new value, should trigger write to injector.
DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
- SettingsEntry overrideSettings = provider.getOverrideSettings(mPrimaryDisplayInfo);
- overrideSettings.mForcedDensity = 200;
- provider.updateOverrideSettings(mPrimaryDisplayInfo, overrideSettings);
+ updateOverrideSettings(provider, mPrimaryDisplayInfo,
+ overrideSettings -> overrideSettings.mForcedDensity = 200);
assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
// Verify that display identifier was updated.
@@ -167,7 +170,7 @@
}
@Test
- public void testReadingDisplaySettingsFromStorage_secondayVendorDisplaySettingsLocation() {
+ public void testReadingDisplaySettingsFromStorage_secondaryVendorDisplaySettingsLocation() {
final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
prepareSecondaryDisplaySettings(displayIdentifier);
@@ -216,11 +219,11 @@
// Write some settings to storage.
DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
- SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
- overrideSettings.mShouldShowSystemDecors = true;
- overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
- overrideSettings.mDontMoveToTop = true;
- provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+ updateOverrideSettings(provider, secondaryDisplayInfo, overrideSettings -> {
+ overrideSettings.mShouldShowSystemDecors = true;
+ overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
+ overrideSettings.mDontMoveToTop = true;
+ });
assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
// Verify that settings were stored correctly.
@@ -235,6 +238,29 @@
}
@Test
+ public void testWritingDisplaySettingsToStorage_secondaryUserDisplaySettingsLocation() {
+ final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
+ mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
+ final DisplayInfo displayInfo = mPrimaryDisplay.getDisplayInfo();
+ final TestStorage secondaryUserOverrideSettingsStorage = new TestStorage();
+ final SettingsEntry expectedSettings = new SettingsEntry();
+ expectedSettings.mForcedDensity = 356;
+
+ // Write some settings to storage from default user.
+ updateOverrideSettings(provider, displayInfo, settings -> settings.mForcedDensity = 356);
+ assertThat(mOverrideSettingsStorage.wasWriteSuccessful()).isTrue();
+
+ // Now switch to secondary user override settings and write some settings.
+ provider.setOverrideSettingsStorage(secondaryUserOverrideSettingsStorage);
+ updateOverrideSettings(provider, displayInfo, settings -> settings.mForcedDensity = 420);
+ assertThat(secondaryUserOverrideSettingsStorage.wasWriteSuccessful()).isTrue();
+
+ // Switch back to primary and assert default user settings remain unchanged.
+ provider.setOverrideSettingsStorage(mOverrideSettingsStorage);
+ assertThat(provider.getOverrideSettings(displayInfo)).isEqualTo(expectedSettings);
+ }
+
+ @Test
public void testDoNotWriteVirtualDisplaySettingsToStorage() throws Exception {
final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
secondaryDisplayInfo.type = TYPE_VIRTUAL;
@@ -242,11 +268,11 @@
// No write to storage on virtual display change.
final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
- final SettingsEntry virtualSettings = provider.getOverrideSettings(secondaryDisplayInfo);
- virtualSettings.mShouldShowSystemDecors = true;
- virtualSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
- virtualSettings.mDontMoveToTop = true;
- provider.updateOverrideSettings(secondaryDisplayInfo, virtualSettings);
+ updateOverrideSettings(provider, secondaryDisplayInfo, virtualSettings -> {
+ virtualSettings.mShouldShowSystemDecors = true;
+ virtualSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
+ virtualSettings.mDontMoveToTop = true;
+ });
assertFalse(mOverrideSettingsStorage.wasWriteSuccessful());
}
@@ -263,10 +289,10 @@
// Write some settings to storage.
DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
- SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
- overrideSettings.mShouldShowSystemDecors = true;
- overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
- provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+ updateOverrideSettings(provider, secondaryDisplayInfo, overrideSettings -> {
+ overrideSettings.mShouldShowSystemDecors = true;
+ overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
+ });
assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
// Verify that settings were stored correctly.
@@ -283,16 +309,16 @@
final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
final int initialSize = provider.getOverrideSettingsSize();
-
- // Size + 1 when query for a new display.
final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
- final SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
- assertEquals(initialSize + 1, provider.getOverrideSettingsSize());
+ updateOverrideSettings(provider, secondaryDisplayInfo, overrideSettings -> {
+ // Size + 1 when query for a new display.
+ assertEquals(initialSize + 1, provider.getOverrideSettingsSize());
- // When a display is removed, its override Settings is not removed if there is any override.
- overrideSettings.mShouldShowSystemDecors = true;
- provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+ // When a display is removed, its override Settings is not removed if there is any
+ // override.
+ overrideSettings.mShouldShowSystemDecors = true;
+ });
provider.onDisplayRemoved(secondaryDisplayInfo);
assertEquals(initialSize + 1, provider.getOverrideSettingsSize());
@@ -309,23 +335,53 @@
final DisplayWindowSettingsProvider provider = new DisplayWindowSettingsProvider(
mDefaultVendorSettingsStorage, mOverrideSettingsStorage);
final int initialSize = provider.getOverrideSettingsSize();
-
- // Size + 1 when query for a new display.
final DisplayInfo secondaryDisplayInfo = mSecondaryDisplay.getDisplayInfo();
secondaryDisplayInfo.type = TYPE_VIRTUAL;
- final SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
- assertEquals(initialSize + 1, provider.getOverrideSettingsSize());
+ updateOverrideSettings(provider, secondaryDisplayInfo, overrideSettings -> {
+ // Size + 1 when query for a new display.
+ assertEquals(initialSize + 1, provider.getOverrideSettingsSize());
- // When a virtual display is removed, its override Settings is removed even if it has
- // override.
- overrideSettings.mShouldShowSystemDecors = true;
- provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
+ // When a virtual display is removed, its override Settings is removed
+ // even if it has override.
+ overrideSettings.mShouldShowSystemDecors = true;
+ });
provider.onDisplayRemoved(secondaryDisplayInfo);
assertEquals(initialSize, provider.getOverrideSettingsSize());
}
+ @Test
+ public void testRemovesStaleDisplaySettings() {
+ assumeTrue(com.android.window.flags.Flags.perUserDisplayWindowSettings());
+
+ final DisplayWindowSettingsProvider provider =
+ new DisplayWindowSettingsProvider(mDefaultVendorSettingsStorage,
+ mOverrideSettingsStorage);
+ final DisplayInfo displayInfo = mSecondaryDisplay.getDisplayInfo();
+ updateOverrideSettings(provider, displayInfo, settings -> settings.mForcedDensity = 356);
+ mRootWindowContainer.removeChild(mSecondaryDisplay);
+
+ provider.removeStaleDisplaySettings(mRootWindowContainer);
+
+ assertThat(mOverrideSettingsStorage.wasWriteSuccessful()).isTrue();
+ assertThat(provider.getOverrideSettingsSize()).isEqualTo(0);
+ }
+
+ /**
+ * Updates the override settings for a specific display.
+ *
+ * @param provider the provider to obtain and update the settings from.
+ * @param displayInfo the information about the display to be updated.
+ * @param modifier a function that modifies the settings for the display.
+ */
+ private static void updateOverrideSettings(DisplayWindowSettingsProvider provider,
+ DisplayInfo displayInfo, Consumer<SettingsEntry> modifier) {
+ final SettingsEntry settings = provider.getOverrideSettings(displayInfo);
+ modifier.accept(settings);
+ provider.updateOverrideSettings(displayInfo, settings);
+ }
+
/**
* Prepares display settings and stores in {@link #mOverrideSettingsStorage}. Uses provided
* display identifier and stores windowingMode=WINDOWING_MODE_PINNED.
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 bdd45c6..74e2d44 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -18,10 +18,6 @@
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_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
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;
@@ -31,9 +27,6 @@
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_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_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;
@@ -45,7 +38,6 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -54,8 +46,6 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -129,200 +119,7 @@
mController = new LetterboxUiController(mWm, mActivity);
}
- // shouldRefreshActivityForCameraCompat
- @Test
- public void testShouldRefreshActivityForCameraCompat_flagIsDisabled_returnsFalse() {
- doReturn(false).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
-
- assertFalse(mController.shouldRefreshActivityForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
- public void testShouldRefreshActivityForCameraCompat_overrideEnabled_returnsFalse() {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
-
- assertFalse(mController.shouldRefreshActivityForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
- public void testShouldRefreshActivityForCameraCompat_propertyIsTrueAndOverride_returnsFalse()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH, /* value */ true);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mController.shouldRefreshActivityForCameraCompat());
- }
-
- @Test
- public void testShouldRefreshActivityForCameraCompat_propertyIsFalse_returnsFalse()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH, /* value */ false);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mController.shouldRefreshActivityForCameraCompat());
- }
-
- @Test
- public void testShouldRefreshActivityForCameraCompat_propertyIsTrue_returnsTrue()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH, /* value */ true);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertTrue(mController.shouldRefreshActivityForCameraCompat());
- }
-
- // shouldRefreshActivityViaPauseForCameraCompat
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
- public void testShouldRefreshActivityViaPauseForCameraCompat_flagIsDisabled_returnsFalse() {
- doReturn(false).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
-
- assertFalse(mController.shouldRefreshActivityViaPauseForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
- public void testShouldRefreshActivityViaPauseForCameraCompat_overrideEnabled_returnsTrue() {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
-
- assertTrue(mController.shouldRefreshActivityViaPauseForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE})
- public void testShouldRefreshActivityViaPauseForCameraCompat_propertyIsFalseAndOverride_returnFalse()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE, /* value */ false);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mController.shouldRefreshActivityViaPauseForCameraCompat());
- }
-
- @Test
- public void testShouldRefreshActivityViaPauseForCameraCompat_propertyIsTrue_returnsTrue()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE, /* value */ true);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertTrue(mController.shouldRefreshActivityViaPauseForCameraCompat());
- }
-
- // shouldForceRotateForCameraCompat
-
- @Test
- public void testShouldForceRotateForCameraCompat_flagIsDisabled_returnsFalse() {
- doReturn(false).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
-
- assertFalse(mController.shouldForceRotateForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION})
- public void testShouldForceRotateForCameraCompat_overrideEnabled_returnsFalse() {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
-
- assertFalse(mController.shouldForceRotateForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION})
- public void testShouldForceRotateForCameraCompat_propertyIsTrueAndOverride_returnsFalse()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, /* value */ true);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mController.shouldForceRotateForCameraCompat());
- }
-
- @Test
- public void testShouldForceRotateForCameraCompat_propertyIsFalse_returnsFalse()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, /* value */ false);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mController.shouldForceRotateForCameraCompat());
- }
-
- @Test
- public void testShouldForceRotateForCameraCompat_propertyIsTrue_returnsTrue()
- throws Exception {
- doReturn(true).when(mLetterboxConfiguration)
- .isCameraCompatTreatmentEnabled();
- mockThatProperty(PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION, /* value */ true);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertTrue(mController.shouldForceRotateForCameraCompat());
- }
-
- // shouldApplyFreeformTreatmentForCameraCompat
-
- @Test
- public void testShouldApplyCameraCompatFreeformTreatment_flagIsDisabled_returnsFalse() {
- mSetFlagsRule.disableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
-
- assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
- public void testShouldApplyCameraCompatFreeformTreatment_overrideEnabled_returnsFalse() {
- mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
-
- assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
- }
-
- @Test
- @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
- public void testShouldApplyCameraCompatFreeformTreatment_disabledByOverride_returnsFalse()
- throws Exception {
- mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
- }
-
- @Test
- public void testShouldApplyCameraCompatFreeformTreatment_notDisabledByOverride_returnsTrue()
- throws Exception {
- mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);
-
- mController = new LetterboxUiController(mWm, mActivity);
-
- assertTrue(mController.shouldApplyFreeformTreatmentForCameraCompat());
- }
@Test
public void testGetCropBoundsIfNeeded_handleCropForTransparentActivityBasedOnOpaqueBounds() {
@@ -641,39 +438,6 @@
assertFalse(mController.shouldApplyUserMinAspectRatioOverride());
}
- @Test
- public void testRecomputeConfigurationForCameraCompatIfNeeded() {
- spyOn(mController);
- doReturn(false).when(mController).isOverrideOrientationOnlyForCameraEnabled();
- doReturn(false).when(mController).isCameraCompatSplitScreenAspectRatioAllowed();
- doReturn(false).when(mController).shouldOverrideMinAspectRatioForCamera();
- clearInvocations(mActivity);
-
- mController.recomputeConfigurationForCameraCompatIfNeeded();
-
- verify(mActivity, never()).recomputeConfiguration();
-
- // isOverrideOrientationOnlyForCameraEnabled
- doReturn(true).when(mController).isOverrideOrientationOnlyForCameraEnabled();
- clearInvocations(mActivity);
- mController.recomputeConfigurationForCameraCompatIfNeeded();
- verify(mActivity).recomputeConfiguration();
-
- // isCameraCompatSplitScreenAspectRatioAllowed
- doReturn(false).when(mController).isOverrideOrientationOnlyForCameraEnabled();
- doReturn(true).when(mController).isCameraCompatSplitScreenAspectRatioAllowed();
- clearInvocations(mActivity);
- mController.recomputeConfigurationForCameraCompatIfNeeded();
- verify(mActivity).recomputeConfiguration();
-
- // shouldOverrideMinAspectRatioForCamera
- doReturn(false).when(mController).isCameraCompatSplitScreenAspectRatioAllowed();
- doReturn(true).when(mController).shouldOverrideMinAspectRatioForCamera();
- clearInvocations(mActivity);
- mController.recomputeConfigurationForCameraCompatIfNeeded();
- verify(mActivity).recomputeConfiguration();
- }
-
private void prepareActivityForShouldApplyUserMinAspectRatioOverride(
boolean orientationRequest) {
spyOn(mController);
@@ -875,7 +639,8 @@
doReturn(true).when(mActivity).isCameraActive();
mController = new LetterboxUiController(mWm, mActivity);
- assertTrue(mController.shouldOverrideMinAspectRatioForCamera());
+ assertTrue(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
@@ -886,7 +651,8 @@
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
mController = new LetterboxUiController(mWm, mActivity);
- assertTrue(mController.shouldOverrideMinAspectRatioForCamera());
+ assertTrue(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
@@ -897,7 +663,8 @@
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldOverrideMinAspectRatioForCamera());
+ assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
@@ -908,7 +675,8 @@
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldOverrideMinAspectRatioForCamera());
+ assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
@@ -917,7 +685,8 @@
doReturn(true).when(mActivity).isCameraActive();
mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldOverrideMinAspectRatioForCamera());
+ assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
@@ -927,7 +696,8 @@
mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ false);
mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldOverrideMinAspectRatioForCamera());
+ assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
@@ -938,7 +708,8 @@
doReturn(true).when(mActivity).isCameraActive();
mController = new LetterboxUiController(mWm, mActivity);
- assertFalse(mController.shouldOverrideMinAspectRatioForCamera());
+ assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
+ .shouldOverrideMinAspectRatioForCamera());
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java
index c5bf78b..7efbc88 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java
@@ -29,7 +29,7 @@
import com.android.internal.protolog.ProtoLogImpl;
import com.android.internal.protolog.common.IProtoLog;
import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.protolog.common.ProtoLog;
+import com.android.internal.protolog.ProtoLog;
import org.junit.After;
import org.junit.Ignore;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index eb79118..3078df0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -392,6 +392,8 @@
assertEquals(newPipTask, mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask());
assertNotEquals(newPipTask, activity1.getTask());
assertFalse("Created PiP task must not be in recents", newPipTask.inRecents);
+ assertThat(newPipTask.autoRemoveRecents).isTrue();
+ assertThat(activity1.getTask().autoRemoveRecents).isFalse();
}
/**
@@ -427,6 +429,7 @@
bounds.scale(0.5f);
task.setBounds(bounds);
assertFalse(activity.isLetterboxedForFixedOrientationAndAspectRatio());
+ assertThat(task.autoRemoveRecents).isFalse();
}
/**
@@ -451,6 +454,7 @@
// Ensure a task has moved over.
ensureTaskPlacement(task, activity);
assertTrue(task.inPinnedWindowingMode());
+ assertThat(task.autoRemoveRecents).isFalse();
}
/**
@@ -480,6 +484,8 @@
ensureTaskPlacement(fullscreenTask, secondActivity);
assertTrue(pinnedRootTask.inPinnedWindowingMode());
assertEquals(WINDOWING_MODE_FULLSCREEN, fullscreenTask.getWindowingMode());
+ assertThat(pinnedRootTask.autoRemoveRecents).isTrue();
+ assertThat(secondActivity.getTask().autoRemoveRecents).isFalse();
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index e01cea3..4bc87b1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -42,6 +42,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
+import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
import static com.android.server.wm.TaskFragment.EMBEDDED_DIM_AREA_PARENT_TASK;
import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
@@ -222,6 +223,27 @@
}
@Test
+ public void testReparentPinnedActivityBackToOriginalTask() {
+ final ActivityRecord activityMain = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final Task originalTask = activityMain.getTask();
+ final ActivityRecord activityPip = new ActivityBuilder(mAtm).setTask(originalTask).build();
+ activityPip.setState(RESUMED, "test");
+ mAtm.mRootWindowContainer.moveActivityToPinnedRootTask(activityPip,
+ null /* launchIntoPipHostActivity */, "test");
+ final Task pinnedActivityTask = activityPip.getTask();
+
+ // Simulate pinnedActivityTask unintentionally added to recent during top activity resume.
+ mAtm.getRecentTasks().getRawTasks().add(pinnedActivityTask);
+
+ // Reparent the activity back to its original task when exiting PIP mode.
+ pinnedActivityTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ assertThat(activityPip.getTask()).isEqualTo(originalTask);
+ assertThat(originalTask.autoRemoveRecents).isFalse();
+ assertThat(mAtm.getRecentTasks().getRawTasks()).containsExactly(originalTask);
+ }
+
+ @Test
public void testReparent_BetweenDisplays() {
// Create first task on primary display.
final Task rootTask1 = createTask(mDisplayContent);
@@ -1991,7 +2013,7 @@
public void getTaskInfoPropagatesCameraCompatMode() {
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
final ActivityRecord activity = task.getTopMostActivity();
- activity.mLetterboxUiController
+ activity.mAppCompatController.getAppCompatCameraOverrides()
.setFreeformCameraCompatMode(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT);
assertEquals(CameraCompatTaskInfo.CAMERA_COMPAT_FREEFORM_PORTRAIT,
diff --git a/telephony/java/android/telephony/satellite/ProvisionSubscriberId.aidl b/telephony/java/android/telephony/satellite/ProvisionSubscriberId.aidl
new file mode 100644
index 0000000..fe46db8
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/ProvisionSubscriberId.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.satellite;
+
+parcelable ProvisionSubscriberId;
diff --git a/telephony/java/android/telephony/satellite/ProvisionSubscriberId.java b/telephony/java/android/telephony/satellite/ProvisionSubscriberId.java
new file mode 100644
index 0000000..796c82d
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/ProvisionSubscriberId.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.satellite;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.telephony.flags.Flags;
+
+import java.util.Objects;
+
+/**
+ * ProvisionSubscriberId
+ *
+ * Satellite Gateway client will use these subscriber ids to register with satellite gateway service
+ * which identify user subscription with unique subscriber ids. These subscriber ids can be any
+ * unique value like iccid, imsi or msisdn which is decided based upon carrier requirements.
+ *
+ * @hide
+ */
+@FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+public final class ProvisionSubscriberId implements Parcelable {
+ /** provision subscriberId */
+ @NonNull
+ private String mSubscriberId;
+
+ /** carrier id */
+ private int mCarrierId;
+
+ /**
+ * @hide
+ */
+ public ProvisionSubscriberId(@NonNull String subscriberId, @NonNull int carrierId) {
+ this.mCarrierId = carrierId;
+ this.mSubscriberId = subscriberId;
+ }
+
+ private ProvisionSubscriberId(Parcel in) {
+ readFromParcel(in);
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeString(mSubscriberId);
+ out.writeInt(mCarrierId);
+ }
+
+ @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+ public static final @android.annotation.NonNull Creator<ProvisionSubscriberId> CREATOR =
+ new Creator<ProvisionSubscriberId>() {
+ @Override
+ public ProvisionSubscriberId createFromParcel(Parcel in) {
+ return new ProvisionSubscriberId(in);
+ }
+
+ @Override
+ public ProvisionSubscriberId[] newArray(int size) {
+ return new ProvisionSubscriberId[size];
+ }
+ };
+
+ /**
+ * @hide
+ */
+ @Override
+ @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * @return token.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+ public String getSubscriberId() {
+ return mSubscriberId;
+ }
+
+ /**
+ * @return carrierId.
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+ public int getCarrierId() {
+ return mCarrierId;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("SubscriberId:");
+ sb.append(mSubscriberId);
+ sb.append(",");
+
+ sb.append("CarrierId:");
+ sb.append(mCarrierId);
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSubscriberId, mCarrierId);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ProvisionSubscriberId that = (ProvisionSubscriberId) o;
+ return mSubscriberId.equals(that.mSubscriberId) && mCarrierId
+ == that.mCarrierId;
+ }
+
+ private void readFromParcel(Parcel in) {
+ mSubscriberId = in.readString();
+ mCarrierId = in.readInt();
+ }
+}
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 6caed14..b518c60d 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -50,6 +50,7 @@
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -233,6 +234,29 @@
public static final String KEY_NTN_SIGNAL_STRENGTH = "ntn_signal_strength";
/**
+ * Bundle key to get the response from
+ * {@link #requestProvisionSubscriberIds(Executor, OutcomeReceiver)}.
+ * @hide
+ */
+ public static final String KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN =
+ "request_provision_subscriber_id";
+
+ /**
+ * Bundle key to get the response from
+ * {@link #requestIsProvisioned(String, Executor, OutcomeReceiver)}.
+ * @hide
+ */
+ public static final String KEY_IS_SATELLITE_PROVISIONED = "request_is_satellite_provisioned";
+
+ /**
+ * Bundle key to get the response from
+ * {@link #provisionSatellite(List, Executor, OutcomeReceiver)}.
+ * @hide
+ */
+ public static final String KEY_PROVISION_SATELLITE_TOKENS = "provision_satellite";
+
+
+ /**
* The request was successfully processed.
*/
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
@@ -2580,6 +2604,179 @@
}
}
+ /**
+ * Request to get list of prioritized satellite subscriber ids to be used for provision.
+ *
+ * Satellite Gateway client will use these subscriber ids to register with satellite gateway
+ * service which identify user subscription with unique subscriber ids. These subscriber ids
+ * can be any unique value like iccid, imsi or msisdn which is decided based upon carrier
+ * requirements.
+ *
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback object to which the result will be delivered.
+ * If successful, the callback returns a list of tokens sorted in ascending priority order index
+ * 0 has the highest priority. Otherwise, it returns an error with a SatelliteException.
+ *
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+ public void requestProvisionSubscriberIds(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<List<ProvisionSubscriberId>, SatelliteException> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ ResultReceiver receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == SATELLITE_RESULT_SUCCESS) {
+ if (resultData.containsKey(KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN)) {
+ List<ProvisionSubscriberId> list =
+ Collections.singletonList(resultData.getParcelable(
+ KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN,
+ ProvisionSubscriberId.class));
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onResult(list)));
+ } else {
+ loge("KEY_REQUEST_PROVISION_SUBSCRIBER_ID_TOKEN does not exist.");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(
+ SATELLITE_RESULT_REQUEST_FAILED))));
+ }
+ } else {
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(resultCode))));
+ }
+ }
+ };
+ telephony.requestProvisionSubscriberIds(receiver);
+ } else {
+ loge("requestProvisionSubscriberIds() invalid telephony");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
+ new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
+ }
+ } catch (RemoteException ex) {
+ loge("requestProvisionSubscriberIds() RemoteException: " + ex);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
+ new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
+ }
+ }
+
+ /**
+ * Request to get provisioned status for given a satellite subscriber id.
+ *
+ * @param satelliteSubscriberId Satellite subscriber id requiring provisioned status check.
+ * @param executor The executor on which the callback will be called.
+ * @param callback callback.
+ *
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+ public void requestIsProvisioned(@NonNull String satelliteSubscriberId,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
+ Objects.requireNonNull(satelliteSubscriberId);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ ResultReceiver receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == SATELLITE_RESULT_SUCCESS) {
+ if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) {
+ boolean isIsProvisioned =
+ resultData.getBoolean(KEY_SATELLITE_PROVISIONED);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onResult(isIsProvisioned)));
+ } else {
+ loge("KEY_REQUEST_PROVISION_TOKENS does not exist.");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(
+ SATELLITE_RESULT_REQUEST_FAILED))));
+ }
+ } else {
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(resultCode))));
+ }
+ }
+ };
+ telephony.requestIsProvisioned(satelliteSubscriberId, receiver);
+ } else {
+ loge("requestIsSatelliteProvisioned() invalid telephony");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
+ new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
+ }
+ } catch (RemoteException ex) {
+ loge("requestIsSatelliteProvisioned() RemoteException: " + ex);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
+ new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
+ }
+ }
+
+ /**
+ * Deliver the list of provisioned satellite subscriber ids.
+ *
+ * @param list List of ProvisionSubscriberId.
+ * @param executor The executor on which the callback will be called.
+ * @param callback The callback object to which the result will be delivered.
+ *
+ * @throws SecurityException if the caller doesn't have required permission.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
+ @FlaggedApi(Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+ public void provisionSatellite(@NonNull List<ProvisionSubscriberId> list,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ ResultReceiver receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == SATELLITE_RESULT_SUCCESS) {
+ if (resultData.containsKey(KEY_PROVISION_SATELLITE_TOKENS)) {
+ boolean isUpdated =
+ resultData.getBoolean(KEY_PROVISION_SATELLITE_TOKENS);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onResult(isUpdated)));
+ } else {
+ loge("KEY_REQUEST_PROVISION_TOKENS does not exist.");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(
+ SATELLITE_RESULT_REQUEST_FAILED))));
+ }
+ } else {
+ executor.execute(() -> Binder.withCleanCallingIdentity(() ->
+ callback.onError(new SatelliteException(resultCode))));
+ }
+ }
+ };
+ telephony.provisionSatellite(list, receiver);
+ } else {
+ loge("provisionSatellite() invalid telephony");
+ executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
+ new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
+ }
+ } catch (RemoteException ex) {
+ loge("provisionSatellite() RemoteException: " + ex);
+ executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
+ new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
+ }
+ }
+
@Nullable
private static ITelephony getITelephony() {
ITelephony binder = ITelephony.Stub.asInterface(TelephonyFrameworkInitializer
diff --git a/telephony/java/android/telephony/satellite/stub/ProvisionSubscriberId.aidl b/telephony/java/android/telephony/satellite/stub/ProvisionSubscriberId.aidl
new file mode 100644
index 0000000..2dc8ffb
--- /dev/null
+++ b/telephony/java/android/telephony/satellite/stub/ProvisionSubscriberId.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.satellite.stub;
+
+/**
+ * {@hide}
+ */
+parcelable ProvisionSubscriberId {
+ /** provision subscriberId */
+ String subscriberId;
+
+ /** carrier id */
+ int mCarrierId;
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 9b01b71..7be52ea 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -78,6 +78,7 @@
import android.telephony.satellite.NtnSignalStrength;
import android.telephony.satellite.SatelliteCapabilities;
import android.telephony.satellite.SatelliteDatagram;
+import android.telephony.satellite.ProvisionSubscriberId;
import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.IBooleanConsumer;
@@ -3400,4 +3401,38 @@
* @hide
*/
void requestSatelliteSessionStats(int subId, in ResultReceiver receiver);
+
+ /**
+ * Request to get list of prioritized satellite subscriber ids to be used for provision.
+ *
+ * @param result The result receiver, which returns the list of prioritized satellite tokens
+ * to be used for provision if the request is successful or an error code if the request failed.
+ * @hide
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void requestProvisionSubscriberIds(in ResultReceiver receiver);
+
+ /**
+ * Request to get provisioned status for given a satellite subscriber id.
+ *
+ * @param satelliteSubscriberId Satellite subscriber id requiring provisioned status check.
+ * @param result The result receiver, which returns the provisioned status of the token if the
+ * request is successful or an error code if the request failed.
+ * @hide
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void requestIsProvisioned(in String satelliteSubscriberId, in ResultReceiver result);
+
+ /**
+ * Deliver the list of provisioned satellite subscriber ids.
+ *
+ * @param list List of provisioned satellite subscriber ids.
+ * @param result The result receiver that returns whether deliver success or fail.
+ * @hide
+ */
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ + "android.Manifest.permission.SATELLITE_COMMUNICATION)")
+ void provisionSatellite(in List<ProvisionSubscriberId> list, in ResultReceiver result);
}
diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
index fff1dd1..ed9c956 100644
--- a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
+++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/ConcurrentMultiUserTest.java
@@ -16,6 +16,8 @@
package com.android.server.inputmethod.multisessiontest;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.compatibility.common.util.concurrentuser.ConcurrentUserActivityUtils.getResponderUserId;
@@ -28,13 +30,21 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.UiAutomation;
import android.content.ComponentName;
+import android.content.Context;
import android.os.Bundle;
+import android.os.UserHandle;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
import androidx.test.core.app.ActivityScenario;
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
+import com.android.compatibility.common.util.SystemUtil;
import org.junit.After;
import org.junit.Before;
@@ -44,8 +54,10 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.IOException;
+import java.util.List;
+
@RunWith(BedsteadJUnit4.class)
-@Ignore("b/345557347")
public final class ConcurrentMultiUserTest {
@ClassRule
@@ -55,6 +67,10 @@
private static final ComponentName TEST_ACTIVITY = new ComponentName(
getInstrumentation().getTargetContext().getPackageName(),
MainActivity.class.getName());
+ private final Context mContext = getInstrumentation().getTargetContext();
+ private final InputMethodManager mInputMethodManager =
+ mContext.getSystemService(InputMethodManager.class);
+ private final UiAutomation mUiAutomation = getInstrumentation().getUiAutomation();
private ActivityScenario<MainActivity> mActivityScenario;
private MainActivity mActivity;
@@ -69,15 +85,18 @@
// Launch driver activity.
mActivityScenario = ActivityScenario.launch(MainActivity.class);
mActivityScenario.onActivity(activity -> mActivity = activity);
+ mUiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_FULL);
}
@After
public void tearDown() {
+ mUiAutomation.dropShellPermissionIdentity();
if (mActivityScenario != null) {
mActivityScenario.close();
}
}
+ @Ignore("b/345557347")
@Test
public void driverShowImeNotAffectPassenger() {
assertDriverImeHidden();
@@ -87,6 +106,58 @@
assertPassengerImeHidden();
}
+ @Test
+ public void imeListNotEmpty() {
+ List<InputMethodInfo> driverImeList = mInputMethodManager.getInputMethodList();
+ assertWithMessage("Driver IME list shouldn't be empty")
+ .that(driverImeList.isEmpty()).isFalse();
+
+ List<InputMethodInfo> passengerImeList =
+ mInputMethodManager.getInputMethodListAsUser(mPeerUserId);
+ assertWithMessage("Passenger IME list shouldn't be empty")
+ .that(passengerImeList.isEmpty()).isFalse();
+ }
+
+ @Test
+ public void enabledImeListNotEmpty() {
+ List<InputMethodInfo> driverEnabledImeList =
+ mInputMethodManager.getEnabledInputMethodList();
+ assertWithMessage("Driver enabled IME list shouldn't be empty")
+ .that(driverEnabledImeList.isEmpty()).isFalse();
+
+ List<InputMethodInfo> passengerEnabledImeList =
+ mInputMethodManager.getEnabledInputMethodListAsUser(UserHandle.of(mPeerUserId));
+ assertWithMessage("Passenger enabled IME list shouldn't be empty")
+ .that(passengerEnabledImeList.isEmpty()).isFalse();
+ }
+
+ @Test
+ public void currentImeNotNull() {
+ InputMethodInfo driverIme = mInputMethodManager.getCurrentInputMethodInfo();
+ assertWithMessage("Driver IME shouldn't be null").that(driverIme).isNotNull();
+
+ InputMethodInfo passengerIme =
+ mInputMethodManager.getCurrentInputMethodInfoAsUser(UserHandle.of(mPeerUserId));
+ assertWithMessage("Passenger IME shouldn't be null")
+ .that(passengerIme).isNotNull();
+ }
+
+ @Test
+ public void enableDisableImePerUser() throws IOException {
+ UserHandle driver = UserHandle.of(mContext.getUserId());
+ UserHandle passenger = UserHandle.of(mPeerUserId);
+ enableDisableImeForUser(driver, passenger);
+ enableDisableImeForUser(passenger, driver);
+ }
+
+ @Test
+ public void setImePerUser() throws IOException {
+ UserHandle driver = UserHandle.of(mContext.getUserId());
+ UserHandle passenger = UserHandle.of(mPeerUserId);
+ setImeForUser(driver, passenger);
+ setImeForUser(passenger, driver);
+ }
+
private void assertDriverImeHidden() {
assertWithMessage("Driver IME should be hidden")
.that(mActivity.isMyImeVisible()).isFalse();
@@ -104,4 +175,89 @@
private void showDriverImeAndAssert() {
mActivity.showMyImeAndWait();
}
+
+ /**
+ * Disables/enables IME for {@code user1}, then verifies that the IME settings for {@code user1}
+ * has changed as expected and {@code user2} stays the same.
+ */
+ private void enableDisableImeForUser(UserHandle user1, UserHandle user2) throws IOException {
+ List<InputMethodInfo> user1EnabledImeList =
+ mInputMethodManager.getEnabledInputMethodListAsUser(user1);
+ List<InputMethodInfo> user2EnabledImeList =
+ mInputMethodManager.getEnabledInputMethodListAsUser(user2);
+
+ // Disable an IME for user1.
+ InputMethodInfo imeToDisable = user1EnabledImeList.get(0);
+ SystemUtil.runShellCommand(mUiAutomation,
+ "ime disable --user " + user1.getIdentifier() + " " + imeToDisable.getId());
+ List<InputMethodInfo> user1EnabledImeList2 =
+ mInputMethodManager.getEnabledInputMethodListAsUser(user1);
+ List<InputMethodInfo> user2EnabledImeList2 =
+ mInputMethodManager.getEnabledInputMethodListAsUser(user2);
+ assertWithMessage("User " + user1.getIdentifier() + " IME " + imeToDisable.getId()
+ + " should be disabled")
+ .that(user1EnabledImeList2.contains(imeToDisable)).isFalse();
+ assertWithMessage("Disabling user " + user1.getIdentifier()
+ + " IME shouldn't affect user " + user2.getIdentifier())
+ .that(user2EnabledImeList2.containsAll(user2EnabledImeList)
+ && user2EnabledImeList.containsAll(user2EnabledImeList2))
+ .isTrue();
+
+ // Enable the IME.
+ SystemUtil.runShellCommand(mUiAutomation,
+ "ime enable --user " + user1.getIdentifier() + " " + imeToDisable.getId());
+ List<InputMethodInfo> user1EnabledImeList3 =
+ mInputMethodManager.getEnabledInputMethodListAsUser(user1);
+ List<InputMethodInfo> user2EnabledImeList3 =
+ mInputMethodManager.getEnabledInputMethodListAsUser(user2);
+ assertWithMessage("User " + user1.getIdentifier() + " IME " + imeToDisable.getId()
+ + " should be enabled").that(user1EnabledImeList3.contains(imeToDisable)).isTrue();
+ assertWithMessage("Enabling user " + user1.getIdentifier()
+ + " IME shouldn't affect user " + user2.getIdentifier())
+ .that(user2EnabledImeList2.containsAll(user2EnabledImeList3)
+ && user2EnabledImeList3.containsAll(user2EnabledImeList2))
+ .isTrue();
+ }
+
+ /**
+ * Sets/resets IME for {@code user1}, then verifies that the IME settings for {@code user1}
+ * has changed as expected and {@code user2} stays the same.
+ */
+ private void setImeForUser(UserHandle user1, UserHandle user2) throws IOException {
+ // Reset IME for user1.
+ SystemUtil.runShellCommand(mUiAutomation,
+ "ime reset --user " + user1.getIdentifier());
+
+ List<InputMethodInfo> user1EnabledImeList =
+ mInputMethodManager.getEnabledInputMethodListAsUser(user1);
+ assumeTrue("There must be at least two IME to test", user1EnabledImeList.size() >= 2);
+ InputMethodInfo user1Ime = mInputMethodManager.getCurrentInputMethodInfoAsUser(user1);
+ InputMethodInfo user2Ime = mInputMethodManager.getCurrentInputMethodInfoAsUser(user2);
+
+ // Set to another IME for user1.
+ InputMethodInfo anotherIme = null;
+ for (InputMethodInfo info : user1EnabledImeList) {
+ if (!info.equals(user1Ime)) {
+ anotherIme = info;
+ }
+ }
+ SystemUtil.runShellCommand(mUiAutomation,
+ "ime set --user " + user1.getIdentifier() + " " + anotherIme.getId());
+ InputMethodInfo user1Ime2 = mInputMethodManager.getCurrentInputMethodInfoAsUser(user1);
+ InputMethodInfo user2Ime2 = mInputMethodManager.getCurrentInputMethodInfoAsUser(user2);
+ assertWithMessage("The current IME for user " + user1.getIdentifier() + " is wrong")
+ .that(user1Ime2).isEqualTo(anotherIme);
+ assertWithMessage("The current IME for user " + user2.getIdentifier() + " shouldn't change")
+ .that(user2Ime2).isEqualTo(user2Ime);
+
+ // Reset IME for user1.
+ SystemUtil.runShellCommand(mUiAutomation,
+ "ime reset --user " + user1.getIdentifier());
+ InputMethodInfo user1Ime3 = mInputMethodManager.getCurrentInputMethodInfoAsUser(user1);
+ InputMethodInfo user2Ime3 = mInputMethodManager.getCurrentInputMethodInfoAsUser(user2);
+ assertWithMessage("The current IME for user " + user1.getIdentifier() + " is wrong")
+ .that(user1Ime3).isEqualTo(user1Ime);
+ assertWithMessage("The current IME for user " + user2.getIdentifier() + " shouldn't change")
+ .that(user2Ime3).isEqualTo(user2Ime);
+ }
}
diff --git a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/MainActivity.java b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/MainActivity.java
index f126000..3c97b79 100644
--- a/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/MainActivity.java
+++ b/tests/inputmethod/ConcurrentMultiSessionImeTest/src/com/android/server/inputmethod/multisessiontest/MainActivity.java
@@ -87,11 +87,13 @@
}
if (!mImm.showSoftInput(mEditor, /* flags= */ 0)) {
Log.e(TAG, String.format("Failed to show my IME as user %d, "
- + "mEditor:focused=%b,hasWindowFocus=%b", getUserId(),
+ + "mEditor:focused=%b,hasWindowFocus=%b",
+ Process.myUserHandle().getIdentifier(),
mEditor.isFocused(), mEditor.hasWindowFocus()));
}
});
PollingCheck.waitFor(WAIT_IME_TIMEOUT_MS, () -> isMyImeVisible(),
- String.format("My IME (user %d) didn't show up", getUserId()));
+ String.format("My IME (user %d) didn't show up",
+ Process.myUserHandle().getIdentifier()));
}
}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 0f1373c..2d5b50b 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -17,7 +17,6 @@
package com.android.protolog.tool
import com.android.internal.protolog.common.LogLevel
-import com.android.internal.protolog.common.ProtoLog
import com.android.internal.protolog.common.ProtoLogToolInjected
import com.android.protolog.tool.CommandOptions.Companion.USAGE
import com.github.javaparser.ParseProblemException
@@ -61,6 +60,8 @@
const val PROTOLOG_IMPL_SRC_PATH =
"frameworks/base/core/java/com/android/internal/protolog/ProtoLogImpl.java"
+ private const val PROTOLOG_CLASS_NAME = "ProtoLog"; // ProtoLog::class.java.simpleName
+
data class LogCall(
val messageString: String,
val logLevel: LogLevel,
@@ -124,7 +125,7 @@
val text = injector.readText(file)
val outSrc = try {
val code = tryParse(text, path)
- if (containsProtoLogText(text, ProtoLog::class.java.simpleName)) {
+ if (containsProtoLogText(text, PROTOLOG_CLASS_NAME)) {
transformer.processClass(text, path, packagePath(file, code), code)
} else {
text
diff --git a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
index 822118c..2a83677 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
@@ -35,7 +35,7 @@
val output = run(
srcs = mapOf("frameworks/base/org/example/Example.java" to """
package org.example;
- import com.android.internal.protolog.common.ProtoLog;
+ import com.android.internal.protolog.ProtoLog;
import static com.android.internal.protolog.ProtoLogGroup.GROUP;
class Example {
@@ -48,7 +48,7 @@
""".trimIndent()),
logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
commandOptions = CommandOptions(arrayOf("transform-protolog-calls",
- "--protolog-class", "com.android.internal.protolog.common.ProtoLog",
+ "--protolog-class", "com.android.internal.protolog.ProtoLog",
"--loggroups-class", "com.android.internal.protolog.ProtoLogGroup",
"--loggroups-jar", "not_required.jar",
"--viewer-config-file-path", "not_required.pb",
@@ -69,7 +69,7 @@
val output = run(
srcs = mapOf("frameworks/base/org/example/Example.java" to """
package org.example;
- import com.android.internal.protolog.common.ProtoLog;
+ import com.android.internal.protolog.ProtoLog;
import static com.android.internal.protolog.ProtoLogGroup.GROUP;
class Example {
@@ -82,7 +82,7 @@
""".trimIndent()),
logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
commandOptions = CommandOptions(arrayOf("generate-viewer-config",
- "--protolog-class", "com.android.internal.protolog.common.ProtoLog",
+ "--protolog-class", "com.android.internal.protolog.ProtoLog",
"--loggroups-class", "com.android.internal.protolog.ProtoLogGroup",
"--loggroups-jar", "not_required.jar",
"--viewer-config-type", "json",