Merge "Dont grant Phone and Calendar permissions to Assistant on non-Wear lowram devices" into main
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/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/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/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/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/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/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index c573cf4a..66b47da 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -92,6 +92,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/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/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/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..5f36e9a 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()
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/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/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..b37db16 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -373,8 +373,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/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/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/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/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/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/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 39cb5a9..9732621 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
@@ -4466,7 +4467,7 @@
}
}
if (mVoicePlaybackActive.getAndSet(voiceActive) != voiceActive) {
- updateHearingAidVolumeOnVoiceActivityUpdate();
+ postUpdateContextualVolumes();
}
if (mMediaPlaybackActive.getAndSet(mediaActive) != mediaActive && mediaActive) {
mSoundDoseHelper.scheduleMusicActiveCheck();
@@ -4604,13 +4605,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));
}
/**
@@ -9812,6 +9829,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/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1e76324..78d501c 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;
@@ -2916,6 +2929,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")
@@ -3101,19 +3117,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 +3281,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 +3299,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()");
@@ -3531,11 +3549,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 +3565,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 +3599,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);
@@ -3945,9 +3962,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 +4009,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.
@@ -4318,13 +4332,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 +4465,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 +4494,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();
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/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/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/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",