Merge "Kill apps when GIDs changed instead of only when added" into main
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ab58f43..8365840 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2925,10 +2925,12 @@
*/
@SuppressWarnings("HiddenAbstractMethod")
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
- public abstract void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent,
+ public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent,
UserHandle user, String[] receiverPermissions, int appOp, Bundle options,
BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
- String initialData, Bundle initialExtras);
+ String initialData, Bundle initialExtras) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
/**
* Version of
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 2ded615..903e916 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -699,6 +699,25 @@
}
/**
+ * Set whether the HAL should ignore display touches.
+ * Only applies to sensors where the HAL is reponsible for handling touches.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouch) {
+ if (mService == null) {
+ Slog.w(TAG, "setIgnoreDisplayTouches: no fingerprint service");
+ return;
+ }
+
+ try {
+ mService.setIgnoreDisplayTouches(requestId, sensorId, ignoreTouch);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Request fingerprint enrollment. This call warms up the fingerprint hardware
* and starts scanning for fingerprints. Progress will be indicated by callbacks to the
* {@link EnrollmentCallback} object. It terminates when
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
index f701ec3..d84d292 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
@@ -120,6 +120,14 @@
}
/**
+ * Returns if sensor type is ultrasonic Udfps
+ * @return true if sensor is ultrasonic Udfps, false otherwise
+ */
+ public boolean isUltrasonicUdfps() {
+ return sensorType == TYPE_UDFPS_ULTRASONIC;
+ }
+
+ /**
* Returns if sensor type is side-FPS
* @return true if sensor is side-fps, false otherwise
*/
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 742fa57..370f097 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -195,6 +195,9 @@
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void onUdfpsUiEvent(int event, long requestId, int sensorId);
+ @EnforcePermission("USE_BIOMETRIC_INTERNAL")
+ void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches);
+
// Sets the controller for managing the UDFPS overlay.
@EnforcePermission("USE_BIOMETRIC_INTERNAL")
void setUdfpsOverlayController(in IUdfpsOverlayController controller);
diff --git a/core/java/android/os/vibrator/VibrationConfig.java b/core/java/android/os/vibrator/VibrationConfig.java
index 555a120..9c2fb7b 100644
--- a/core/java/android/os/vibrator/VibrationConfig.java
+++ b/core/java/android/os/vibrator/VibrationConfig.java
@@ -70,7 +70,7 @@
private final boolean mDefaultKeyboardVibrationEnabled;
- private final boolean mHasFixedKeyboardAmplitude;
+ private final boolean mKeyboardVibrationSettingsSupported;
/** @hide */
public VibrationConfig(@Nullable Resources resources) {
@@ -89,8 +89,8 @@
com.android.internal.R.bool.config_ignoreVibrationsOnWirelessCharger, false);
mDefaultKeyboardVibrationEnabled = loadBoolean(resources,
com.android.internal.R.bool.config_defaultKeyboardVibrationEnabled, true);
- mHasFixedKeyboardAmplitude = loadFloat(resources,
- com.android.internal.R.dimen.config_keyboardHapticFeedbackFixedAmplitude, -1) > 0;
+ mKeyboardVibrationSettingsSupported = loadBoolean(resources,
+ com.android.internal.R.bool.config_keyboardVibrationSettingsSupported, false);
mDefaultAlarmVibrationIntensity = loadDefaultIntensity(resources,
com.android.internal.R.integer.config_defaultAlarmVibrationIntensity);
@@ -202,11 +202,11 @@
}
/**
- * Whether the device has a fixed amplitude for keyboard.
+ * Whether the device support keyboard vibration settings.
* @hide
*/
- public boolean hasFixedKeyboardAmplitude() {
- return mHasFixedKeyboardAmplitude;
+ public boolean isKeyboardVibrationSettingsSupported() {
+ return mKeyboardVibrationSettingsSupported;
}
/** Get the default vibration intensity for given usage. */
@@ -249,6 +249,7 @@
+ ", mDefaultNotificationIntensity=" + mDefaultNotificationVibrationIntensity
+ ", mDefaultRingIntensity=" + mDefaultRingVibrationIntensity
+ ", mDefaultKeyboardVibrationEnabled=" + mDefaultKeyboardVibrationEnabled
+ + ", mKeyboardVibrationSettingsSupported=" + mKeyboardVibrationSettingsSupported
+ "}";
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 766e02b..4766942 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13859,11 +13859,6 @@
})
@ResolvedLayoutDir
public int getLayoutDirection() {
- final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
- if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
- mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED;
- return LAYOUT_DIRECTION_RESOLVED_DEFAULT;
- }
return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ==
PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
}
diff --git a/core/java/android/window/TaskFragmentAnimationParams.java b/core/java/android/window/TaskFragmentAnimationParams.java
index 85e96c9..67b22f9 100644
--- a/core/java/android/window/TaskFragmentAnimationParams.java
+++ b/core/java/android/window/TaskFragmentAnimationParams.java
@@ -171,7 +171,7 @@
*/
public boolean hasOverrideAnimation() {
return mOpenAnimationResId != DEFAULT_ANIMATION_RESOURCES_ID
- || mChangeAnimationResId != DEFAULT_ANIMATION_BACKGROUND_COLOR
+ || mChangeAnimationResId != DEFAULT_ANIMATION_RESOURCES_ID
|| mCloseAnimationResId != DEFAULT_ANIMATION_RESOURCES_ID;
}
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index d0ab674..1c7acd4 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -127,3 +127,10 @@
description: "Whether to show developer option for enabling desktop windowing mode"
bug: "348193756"
}
+
+flag {
+ name: "enable_desktop_windowing_app_to_web"
+ namespace: "lse_desktop_experience"
+ description: "Whether to enable the app-to-web feature and show the open in browser button in the header menu"
+ bug: "349695493"
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f61b6bf..9f00d5e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -843,6 +843,7 @@
<protected-broadcast android:name="android.intent.action.PROFILE_UNAVAILABLE" />
<protected-broadcast android:name="android.app.action.CONSOLIDATED_NOTIFICATION_POLICY_CHANGED" />
<protected-broadcast android:name="android.intent.action.MAIN_USER_LOCKSCREEN_KNOWLEDGE_FACTOR_CHANGED" />
+ <protected-broadcast android:name="com.android.uwb.uwbcountrycode.GEOCODE_RETRY" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 335b740..ca80e22 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4136,6 +4136,9 @@
<!-- The default value for keyboard vibration toggle in settings. -->
<bool name="config_defaultKeyboardVibrationEnabled">true</bool>
+ <!-- Indicating if keyboard vibration settings supported or not. -->
+ <bool name="config_keyboardVibrationSettingsSupported">false</bool>
+
<!-- If the device should still vibrate even in low power mode, for certain priority vibrations
(e.g. accessibility, alarms). This is mainly for Wear devices that don't have speakers. -->
<bool name="config_allowPriorityVibrationsInLowPowerMode">false</bool>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 61c7a8c..cdd8557 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -393,6 +393,12 @@
<bool name="config_wait_for_device_alignment_in_demo_datagram">false</bool>
<java-symbol type="bool" name="config_wait_for_device_alignment_in_demo_datagram" />
+ <!-- Boolean indicating whether to enable MMS to be attempted on IWLAN if possible, even if
+ existing cellular networks already supports IWLAN.
+ -->
+ <bool name="force_iwlan_mms_feature_enabled">false</bool>
+ <java-symbol type="bool" name="force_iwlan_mms_feature_enabled" />
+
<!-- The time duration in millis after which Telephony will abort the last message datagram
sending requests. Telephony starts a timer when receiving a last message datagram sending
request in either OFF, IDLE, or NOT_CONNECTED state. In NOT_CONNECTED, the duration of the
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 26f153a..9661b46 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2126,6 +2126,7 @@
<java-symbol type="dimen" name="config_hapticChannelMaxVibrationAmplitude" />
<java-symbol type="dimen" name="config_keyboardHapticFeedbackFixedAmplitude" />
<java-symbol type="bool" name="config_defaultKeyboardVibrationEnabled" />
+ <java-symbol type="bool" name="config_keyboardVibrationSettingsSupported" />
<java-symbol type="integer" name="config_vibrationWaveformRampStepDuration" />
<java-symbol type="bool" name="config_ignoreVibrationsOnWirelessCharger" />
<java-symbol type="integer" name="config_vibrationWaveformRampDownDuration" />
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 612b387..9ea2943 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizer.java
@@ -50,6 +50,7 @@
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -393,19 +394,31 @@
if (splitAttributes == null) {
return TaskFragmentAnimationParams.DEFAULT;
}
+ final TaskFragmentAnimationParams.Builder builder =
+ new TaskFragmentAnimationParams.Builder();
final int animationBackgroundColor = getAnimationBackgroundColor(splitAttributes);
- TaskFragmentAnimationParams.Builder builder = new TaskFragmentAnimationParams.Builder();
- if (animationBackgroundColor != DEFAULT_ANIMATION_BACKGROUND_COLOR) {
- builder.setAnimationBackgroundColor(animationBackgroundColor);
+ builder.setAnimationBackgroundColor(animationBackgroundColor);
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ final int openAnimationResId =
+ splitAttributes.getAnimationParams().getOpenAnimationResId();
+ builder.setOpenAnimationResId(openAnimationResId);
+ final int closeAnimationResId =
+ splitAttributes.getAnimationParams().getCloseAnimationResId();
+ builder.setCloseAnimationResId(closeAnimationResId);
+ final int changeAnimationResId =
+ splitAttributes.getAnimationParams().getChangeAnimationResId();
+ builder.setChangeAnimationResId(changeAnimationResId);
}
- // 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();
+ AnimationBackground animationBackground = splitAttributes.getAnimationBackground();
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ animationBackground = splitAttributes.getAnimationParams().getAnimationBackground();
+ }
if (animationBackground instanceof AnimationBackground.ColorBackground colorBackground) {
animationBackgroundColor = colorBackground.getColor();
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
index 4267749..c5aaddc 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
@@ -29,6 +29,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.window.extensions.embedding.AnimationBackground;
+import androidx.window.extensions.embedding.AnimationParams;
import androidx.window.extensions.embedding.SplitAttributes;
import org.junit.Before;
@@ -112,5 +113,13 @@
.isEqualTo(new SplitAttributes.SplitType.RatioSplitType(0.5f));
assertThat(splitAttributes.getAnimationBackground())
.isEqualTo(AnimationBackground.ANIMATION_BACKGROUND_DEFAULT);
+ assertThat(splitAttributes.getAnimationParams().getAnimationBackground())
+ .isEqualTo(AnimationBackground.ANIMATION_BACKGROUND_DEFAULT);
+ assertThat(splitAttributes.getAnimationParams().getOpenAnimationResId())
+ .isEqualTo(AnimationParams.DEFAULT_ANIMATION_RESOURCES_ID);
+ assertThat(splitAttributes.getAnimationParams().getCloseAnimationResId())
+ .isEqualTo(AnimationParams.DEFAULT_ANIMATION_RESOURCES_ID);
+ assertThat(splitAttributes.getAnimationParams().getChangeAnimationResId())
+ .isEqualTo(AnimationParams.DEFAULT_ANIMATION_RESOURCES_ID);
}
}
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp b/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp
index c6dbd9b..1871203 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/Android.bp
@@ -22,6 +22,40 @@
default_team: "trendy_team_multitasking_windowing",
}
+android_app {
+ name: "WMShellRobolectricScreenshotTestApp",
+ platform_apis: true,
+ certificate: "platform",
+ static_libs: [
+ "WindowManager-Shell",
+ "platform-screenshot-diff-core",
+ ],
+ asset_dirs: ["goldens/robolectric"],
+ manifest: "AndroidManifestRobolectric.xml",
+ use_resource_processor: true,
+}
+
+android_robolectric_test {
+ name: "WMShellRobolectricScreenshotTests",
+ instrumentation_for: "WMShellRobolectricScreenshotTestApp",
+ upstream: true,
+ java_resource_dirs: [
+ "robolectric/config",
+ ],
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "junit",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "truth",
+ "platform-parametric-runner-lib",
+ ],
+ auto_gen_config: true,
+}
+
android_test {
name: "WMShellMultivalentScreenshotTestsOnDevice",
srcs: [
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/AndroidManifestRobolectric.xml b/libs/WindowManager/Shell/multivalentScreenshotTests/AndroidManifestRobolectric.xml
index a7a3f13..b4bdaea 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/AndroidManifestRobolectric.xml
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/AndroidManifestRobolectric.xml
@@ -16,7 +16,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.wm.shell.multivalentscreenshot">
<application android:debuggable="true" android:supportsRtl="true">
- <uses-library android:name="android.test.runner" />
<activity
android:name="platform.test.screenshot.ScreenshotActivity"
android:exported="true">
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/dark_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/dark_portrait_bubbles_education.png
new file mode 100644
index 0000000..723c6b8
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/dark_portrait_bubbles_education.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/light_portrait_bubbles_education.png b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/light_portrait_bubbles_education.png
new file mode 100644
index 0000000..723c6b8
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/goldens/robolectric/phone/light_portrait_bubbles_education.png
Binary files differ
diff --git a/libs/WindowManager/Shell/multivalentScreenshotTests/robolectric/config/robolectric.properties b/libs/WindowManager/Shell/multivalentScreenshotTests/robolectric/config/robolectric.properties
index 7a0527c..d50d976 100644
--- a/libs/WindowManager/Shell/multivalentScreenshotTests/robolectric/config/robolectric.properties
+++ b/libs/WindowManager/Shell/multivalentScreenshotTests/robolectric/config/robolectric.properties
@@ -1,2 +1,3 @@
sdk=NEWEST_SDK
+graphicsMode=NATIVE
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt
index dfc9c82..8f7fdd6 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlags.kt
@@ -37,15 +37,12 @@
// All desktop mode related flags will be added here
DESKTOP_WINDOWING_MODE(DesktopModeStatus::isDesktopModeFlagEnabled, true);
- private val TAG = "DesktopModeFlags"
-
- // Cache for toggle override, which is initialized once on its first access. It needs to be refreshed
- // only on reboots as overridden state takes effect on reboots.
+ // Local cache for toggle override, which is initialized once on its first access. It needs to be
+ // refreshed only on reboots as overridden state takes effect on reboots.
private var cachedToggleOverride: ToggleOverride? = null
/**
- * Determines state of flag based on the actual flag and desktop mode developer option
- * overrides.
+ * Determines state of flag based on the actual flag and desktop mode developer option overrides.
*
* Note, this method makes sure that a constant developer toggle overrides is read until reboot.
*/
@@ -63,34 +60,44 @@
}
private fun getToggleOverride(context: Context): ToggleOverride {
- val override = cachedToggleOverride ?: run {
- // Cache toggle override the first time we encounter context. Override does not change
- // with context, as context is just used to fetch a system property.
-
- // TODO(b/348193756): Cache a persistent value for Settings.Global until reboot. Current
- // cache will change with process restart.
- val toggleOverride =
- Settings.Global.getInt(
- context.contentResolver,
- Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
- ToggleOverride.OVERRIDE_UNSET.setting)
-
- val newOverride =
- settingToToggleOverrideMap[toggleOverride]
- ?: run {
- Log.w(TAG, "Unknown toggleOverride $toggleOverride")
- ToggleOverride.OVERRIDE_UNSET
- }
- cachedToggleOverride = newOverride
- Log.d(TAG, "Toggle override initialized to: $newOverride")
- newOverride
- }
+ val override =
+ cachedToggleOverride
+ ?: run {
+ val override = getToggleOverrideFromSystem(context)
+ // Cache toggle override the first time we encounter context. Override does not change
+ // with context, as context is just used to fetch System Property and Settings.Global
+ cachedToggleOverride = override
+ Log.d(TAG, "Toggle override initialized to: $override")
+ override
+ }
return override
}
- // TODO(b/348193756): Share ToggleOverride enum with Settings
- // 'DesktopModePreferenceController'
+ private fun getToggleOverrideFromSystem(context: Context): ToggleOverride {
+ // A non-persistent System Property is used to store override to ensure it remains
+ // constant till reboot.
+ val overrideFromSystemProperties: ToggleOverride? =
+ System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, null).convertToToggleOverride()
+ return overrideFromSystemProperties
+ ?: run {
+ // Read Setting Global if System Property is not present (just after reboot)
+ // or not valid (user manually changed the value)
+ val overrideFromSettingsGlobal =
+ Settings.Global.getInt(
+ context.contentResolver,
+ Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES,
+ ToggleOverride.OVERRIDE_UNSET.setting)
+ .convertToToggleOverrideWithFallback(ToggleOverride.OVERRIDE_UNSET)
+ // Initialize System Property
+ System.setProperty(
+ SYSTEM_PROPERTY_OVERRIDE_KEY, overrideFromSettingsGlobal.setting.toString())
+
+ overrideFromSettingsGlobal
+ }
+ }
+
+ // TODO(b/348193756): Share ToggleOverride enum with Settings 'DesktopModePreferenceController'
/**
* Override state of desktop mode developer option toggle.
*
@@ -107,4 +114,33 @@
}
private val settingToToggleOverrideMap = ToggleOverride.entries.associateBy { it.setting }
+
+ private fun String?.convertToToggleOverride(): ToggleOverride? {
+ val intValue = this?.toIntOrNull() ?: return null
+ return settingToToggleOverrideMap[intValue]
+ ?: run {
+ Log.w(TAG, "Unknown toggleOverride int $intValue")
+ null
+ }
+ }
+
+ private fun Int.convertToToggleOverrideWithFallback(
+ fallbackOverride: ToggleOverride
+ ): ToggleOverride {
+ return settingToToggleOverrideMap[this]
+ ?: run {
+ Log.w(TAG, "Unknown toggleOverride int $this")
+ fallbackOverride
+ }
+ }
+
+ private companion object {
+ const val TAG = "DesktopModeFlags"
+
+ /**
+ * Key for non-persistent System Property which is used to store desktop windowing developer
+ * option overrides.
+ */
+ const val SYSTEM_PROPERTY_OVERRIDE_KEY = "sys.wmshell.desktopmode.dev_toggle_override"
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index d270d2b..5696a54 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -266,6 +266,9 @@
final Animation animation =
animationProvider.get(info, change, openingWholeScreenBounds);
if (shouldUseJumpCutForAnimation(animation)) {
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ return new ArrayList<>();
+ }
continue;
}
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
@@ -291,6 +294,9 @@
final Animation animation =
animationProvider.get(info, change, closingWholeScreenBounds);
if (shouldUseJumpCutForAnimation(animation)) {
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ return new ArrayList<>();
+ }
continue;
}
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index f49b90d0..3046307 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -97,7 +97,7 @@
Animation createChangeBoundsOpenAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) {
if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
- final Animation customAnimation = loadCustomAnimation(info, change);
+ final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE);
if (customAnimation != null) {
return customAnimation;
}
@@ -131,7 +131,7 @@
Animation createChangeBoundsCloseAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, @NonNull Rect parentBounds) {
if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
- final Animation customAnimation = loadCustomAnimation(info, change);
+ final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE);
if (customAnimation != null) {
return customAnimation;
}
@@ -172,7 +172,7 @@
// TODO(b/293658614): Support more complicated animations that may need more than a noop
// animation as the start leash.
final Animation noopAnimation = createNoopAnimation(change);
- final Animation customAnimation = loadCustomAnimation(info, change);
+ final Animation customAnimation = loadCustomAnimation(info, change, TRANSIT_CHANGE);
if (customAnimation != null) {
return new Animation[]{noopAnimation, customAnimation};
}
@@ -227,7 +227,7 @@
Animation loadOpenAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
final boolean isEnter = TransitionUtil.isOpeningType(change.getMode());
- final Animation customAnimation = loadCustomAnimation(info, change);
+ final Animation customAnimation = loadCustomAnimation(info, change, change.getMode());
final Animation animation;
if (customAnimation != null) {
animation = customAnimation;
@@ -254,7 +254,7 @@
Animation loadCloseAnimation(@NonNull TransitionInfo info,
@NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
final boolean isEnter = TransitionUtil.isOpeningType(change.getMode());
- final Animation customAnimation = loadCustomAnimation(info, change);
+ final Animation customAnimation = loadCustomAnimation(info, change, change.getMode());
final Animation animation;
if (customAnimation != null) {
animation = customAnimation;
@@ -287,14 +287,14 @@
@Nullable
private Animation loadCustomAnimation(@NonNull TransitionInfo info,
- @NonNull TransitionInfo.Change change) {
+ @NonNull TransitionInfo.Change change, @WindowManager.TransitionType int mode) {
final TransitionInfo.AnimationOptions options;
if (Flags.moveAnimationOptionsToChange()) {
options = change.getAnimationOptions();
} else {
options = info.getAnimationOptions();
}
- return loadCustomAnimationFromOptions(options, change.getMode());
+ return loadCustomAnimationFromOptions(options, mode);
}
@Nullable
@@ -319,8 +319,14 @@
return null;
}
- final Animation anim = mTransitionAnimation.loadAnimationRes(options.getPackageName(),
- resId);
+ final Animation anim;
+ if (Flags.activityEmbeddingAnimationCustomizationFlag()) {
+ // TODO(b/293658614): Consider allowing custom animations from non-default packages.
+ // Enforce limiting to animations from the default "android" package for now.
+ anim = mTransitionAnimation.loadDefaultAnimationRes(resId);
+ } else {
+ anim = mTransitionAnimation.loadAnimationRes(options.getPackageName(), resId);
+ }
if (anim != null) {
return anim;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index da1d6da..e792f7a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -24,7 +24,6 @@
import android.os.UserManager;
import android.view.Choreographer;
import android.view.IWindowManager;
-import android.view.SurfaceControl;
import android.view.WindowManager;
import com.android.internal.jank.InteractionJankMonitor;
@@ -404,8 +403,7 @@
Optional<RecentTasksController> recentTasksController,
HomeTransitionObserver homeTransitionObserver) {
return new RecentsTransitionHandler(shellInit, transitions,
- recentTasksController.orElse(null), homeTransitionObserver,
- SurfaceControl.Transaction::new);
+ recentTasksController.orElse(null), homeTransitionObserver);
}
//
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 e46625d..234b4d0 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
@@ -74,7 +74,6 @@
import java.util.ArrayList;
import java.util.function.Consumer;
-import java.util.function.Supplier;
/**
* Handles the Recents (overview) animation. Only one of these can run at a time. A recents
@@ -85,7 +84,6 @@
private final Transitions mTransitions;
private final ShellExecutor mExecutor;
- private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
@Nullable
private final RecentTasksController mRecentTasksController;
private IApplicationThread mAnimApp = null;
@@ -103,13 +101,11 @@
public RecentsTransitionHandler(ShellInit shellInit, Transitions transitions,
@Nullable RecentTasksController recentTasksController,
- HomeTransitionObserver homeTransitionObserver,
- Supplier<SurfaceControl.Transaction> transactionSupplier) {
+ HomeTransitionObserver homeTransitionObserver) {
mTransitions = transitions;
mExecutor = transitions.getMainExecutor();
mRecentTasksController = recentTasksController;
mHomeTransitionObserver = homeTransitionObserver;
- mTransactionSupplier = transactionSupplier;
if (!Transitions.ENABLE_SHELL_TRANSITIONS) return;
if (recentTasksController == null) return;
shellInit.addInitCallback(() -> {
@@ -1060,7 +1056,7 @@
final Transitions.TransitionFinishCallback finishCB = mFinishCB;
mFinishCB = null;
- SurfaceControl.Transaction t = mFinishTransaction;
+ final SurfaceControl.Transaction t = mFinishTransaction;
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (mKeyguardLocked && mRecentsTask != null) {
@@ -1110,16 +1106,6 @@
}
}
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, " normal finish");
- if (toHome && !mOpeningTasks.isEmpty()) {
- // Attempting to start a task after swipe to home, don't show it,
- // move recents to top
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
- " attempting to start a task after swipe to home");
- t = mTransactionSupplier.get();
- wct.reorder(mRecentsTask, true /*onTop*/);
- mClosingTasks.addAll(mOpeningTasks);
- mOpeningTasks.clear();
- }
// The general case: committing to recents, going home, or switching tasks.
for (int i = 0; i < mOpeningTasks.size(); ++i) {
t.show(mOpeningTasks.get(i).mTaskSurface);
@@ -1188,10 +1174,6 @@
mPipTransaction = null;
}
}
- if (t != mFinishTransaction) {
- // apply after merges because these changes are accounting for finishWCT changes.
- mTransitions.setAfterMergeFinishTransaction(mTransition, t);
- }
cleanUp();
finishCB.onTransitionFinished(wct.isEmpty() ? null : wct);
if (runnerFinishCb != null) {
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 b8abf8f..bd25846 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
@@ -242,13 +242,6 @@
/** Ordered list of transitions which have been merged into this one. */
private ArrayList<ActiveTransition> mMerged;
- /**
- * @deprecated DO NOT USE THIS unless absolutely necessary. It will be removed once
- * everything migrates off finishWCT.
- */
- @java.lang.Deprecated
- SurfaceControl.Transaction mAfterMergeFinishT;
-
ActiveTransition(IBinder token) {
mToken = token;
}
@@ -1034,20 +1027,6 @@
return null;
}
- /** @deprecated */
- @java.lang.Deprecated
- public void setAfterMergeFinishTransaction(IBinder transition,
- SurfaceControl.Transaction afterMergeFinishT) {
- final ActiveTransition at = mKnownTransitions.get(transition);
- if (at == null) return;
- if (at.mAfterMergeFinishT != null) {
- Log.e(TAG, "Setting after-merge-t >1 time on transition: " + at.mInfo.getDebugId());
- at.mAfterMergeFinishT.merge(afterMergeFinishT);
- return;
- }
- at.mAfterMergeFinishT = afterMergeFinishT;
- }
-
/** Aborts a transition. This will still queue it up to maintain order. */
private void onAbort(ActiveTransition transition) {
final Track track = mTracks.get(transition.getTrack());
@@ -1108,7 +1087,6 @@
}
// Merge all associated transactions together
SurfaceControl.Transaction fullFinish = active.mFinishT;
- SurfaceControl.Transaction afterMergeFinish = active.mAfterMergeFinishT;
if (active.mMerged != null) {
for (int iM = 0; iM < active.mMerged.size(); ++iM) {
final ActiveTransition toMerge = active.mMerged.get(iM);
@@ -1128,21 +1106,6 @@
fullFinish.merge(toMerge.mFinishT);
}
}
- if (toMerge.mAfterMergeFinishT != null) {
- if (afterMergeFinish == null) {
- afterMergeFinish = toMerge.mAfterMergeFinishT;
- } else {
- afterMergeFinish.merge(toMerge.mAfterMergeFinishT);
- }
- toMerge.mAfterMergeFinishT = null;
- }
- }
- }
- if (afterMergeFinish != null) {
- if (fullFinish == null) {
- fullFinish = afterMergeFinish;
- } else {
- fullFinish.merge(afterMergeFinish);
}
}
if (fullFinish != null) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt
index 115b218..17983b2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeFlagsTest.kt
@@ -82,7 +82,7 @@
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_unsetOverride_featureFlagOn_returnsTrue() {
+ fun isEnabled_overrideUnset_featureFlagOn_returnsTrue() {
setOverride(OVERRIDE_UNSET.setting)
// For overridableFlag, for unset overrides, follow flag
@@ -92,7 +92,7 @@
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_unsetOverride_featureFlagOff_returnsFalse() {
+ fun isEnabled_overrideUnset_featureFlagOff_returnsFalse() {
setOverride(OVERRIDE_UNSET.setting)
// For overridableFlag, for unset overrides, follow flag
@@ -101,7 +101,7 @@
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_noOverride_featureFlagOn_returnsTrue() {
+ fun isEnabled_noOverride_featureFlagOn_returnsTrue() {
setOverride(null)
// For overridableFlag, in absence of overrides, follow flag
@@ -111,7 +111,7 @@
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_noOverride_featureFlagOff_returnsFalse() {
+ fun isEnabled_noOverride_featureFlagOff_returnsFalse() {
setOverride(null)
// For overridableFlag, in absence of overrides, follow flag
@@ -120,7 +120,7 @@
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_unrecognizableOverride_featureFlagOn_returnsTrue() {
+ fun isEnabled_unrecognizableOverride_featureFlagOn_returnsTrue() {
setOverride(-2)
// For overridableFlag, for recognizable overrides, follow flag
@@ -130,7 +130,7 @@
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_unrecognizableOverride_featureFlagOff_returnsFalse() {
+ fun isEnabled_unrecognizableOverride_featureFlagOff_returnsFalse() {
setOverride(-2)
// For overridableFlag, for recognizable overrides, follow flag
@@ -139,7 +139,7 @@
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_overrideOff_featureFlagOn_returnsFalse() {
+ fun isEnabled_overrideOff_featureFlagOn_returnsFalse() {
setOverride(OVERRIDE_OFF.setting)
// For overridableFlag, follow override if they exist
@@ -149,7 +149,7 @@
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_overrideOn_featureFlagOff_returnsTrue() {
+ fun isEnabled_overrideOn_featureFlagOff_returnsTrue() {
setOverride(OVERRIDE_ON.setting)
// For overridableFlag, follow override if they exist
@@ -158,7 +158,7 @@
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() {
+ fun isEnabled_overrideOffThenOn_featureFlagOn_returnsFalseAndFalse() {
setOverride(OVERRIDE_OFF.setting)
// For overridableFlag, follow override if they exist
@@ -173,7 +173,7 @@
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
@DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() {
+ fun isEnabled_overrideOnThenOff_featureFlagOff_returnsTrueAndTrue() {
setOverride(OVERRIDE_ON.setting)
// For overridableFlag, follow override if they exist
@@ -187,7 +187,7 @@
@Test
@EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
- fun isEnabled_flagOverridable_noOverride_featureFlagOnThenOff_returnsTrueAndFalse() {
+ fun isEnabled_noOverride_featureFlagOnThenOff_returnsTrueAndFalse() {
setOverride(null)
// For overridableFlag, in absence of overrides, follow flag
assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
@@ -206,6 +206,108 @@
}
}
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
+ @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ fun isEnabled_noSystemProperty_overrideOn_featureFlagOff_returnsTrueAndStoresPropertyOn() {
+ System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
+ setOverride(OVERRIDE_ON.setting)
+
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
+ // Store System Property if not present
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_ON.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ fun isEnabled_noSystemProperty_overrideUnset_featureFlagOn_returnsTrueAndStoresPropertyUnset() {
+ System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
+ setOverride(OVERRIDE_UNSET.setting)
+
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
+ // Store System Property if not present
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_UNSET.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
+ @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ fun isEnabled_noSystemProperty_overrideUnset_featureFlagOff_returnsFalseAndStoresPropertyUnset() {
+ System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
+ setOverride(OVERRIDE_UNSET.setting)
+
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
+ // Store System Property if not present
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_UNSET.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ @Suppress("ktlint:standard:max-line-length")
+ fun isEnabled_systemPropertyNotInteger_overrideOff_featureFlagOn_returnsFalseAndStoresPropertyOff() {
+ System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "abc")
+ setOverride(OVERRIDE_OFF.setting)
+
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
+ // Store System Property if currently invalid
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_OFF.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ @Suppress("ktlint:standard:max-line-length")
+ fun isEnabled_systemPropertyInvalidInteger_overrideOff_featureFlagOn_returnsFalseAndStoresPropertyOff() {
+ System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, "-2")
+ setOverride(OVERRIDE_OFF.setting)
+
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
+ // Store System Property if currently invalid
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_OFF.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ fun isEnabled_systemPropertyOff_overrideOn_featureFlagOn_returnsFalseAndDoesNotUpdateProperty() {
+ System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_OFF.setting.toString())
+ setOverride(OVERRIDE_ON.setting)
+
+ // Have a consistent override until reboot
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isFalse()
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_OFF.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION)
+ @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ fun isEnabled_systemPropertyOn_overrideOff_featureFlagOff_returnsTrueAndDoesNotUpdateProperty() {
+ System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_ON.setting.toString())
+ setOverride(OVERRIDE_OFF.setting)
+
+ // Have a consistent override until reboot
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_ON.setting.toString())
+ }
+
+ @Test
+ @EnableFlags(FLAG_SHOW_DESKTOP_WINDOWING_DEV_OPTION, FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ @Suppress("ktlint:standard:max-line-length")
+ fun isEnabled_systemPropertyUnset_overrideOff_featureFlagOn_returnsTrueAndDoesNotUpdateProperty() {
+ System.setProperty(SYSTEM_PROPERTY_OVERRIDE_KEY, OVERRIDE_UNSET.setting.toString())
+ setOverride(OVERRIDE_OFF.setting)
+
+ // Have a consistent override until reboot
+ assertThat(DESKTOP_WINDOWING_MODE.isEnabled(mContext)).isTrue()
+ assertThat(System.getProperty(SYSTEM_PROPERTY_OVERRIDE_KEY))
+ .isEqualTo(OVERRIDE_UNSET.setting.toString())
+ }
+
private fun setOverride(setting: Int?) {
val contentResolver = mContext.contentResolver
val key = Settings.Global.DEVELOPMENT_OVERRIDE_DESKTOP_MODE_FEATURES
@@ -217,9 +319,16 @@
}
private fun resetCache() {
- val cacheToggleOverride =
+ val cachedToggleOverride =
DESKTOP_WINDOWING_MODE::class.java.getDeclaredField("cachedToggleOverride")
- cacheToggleOverride.isAccessible = true
- cacheToggleOverride.set(DESKTOP_WINDOWING_MODE, null)
+ cachedToggleOverride.isAccessible = true
+ cachedToggleOverride.set(DESKTOP_WINDOWING_MODE, null)
+
+ // Clear override cache stored in System property
+ System.clearProperty(SYSTEM_PROPERTY_OVERRIDE_KEY)
+ }
+
+ private companion object {
+ const val SYSTEM_PROPERTY_OVERRIDE_KEY = "sys.wmshell.desktopmode.dev_toggle_override"
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 8331d59..409b877 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -1191,8 +1191,7 @@
mMainHandler, mAnimExecutor, mock(HomeTransitionObserver.class));
final RecentsTransitionHandler recentsHandler =
new RecentsTransitionHandler(shellInit, transitions,
- mock(RecentTasksController.class), mock(HomeTransitionObserver.class),
- () -> mock(SurfaceControl.Transaction.class));
+ mock(RecentTasksController.class), mock(HomeTransitionObserver.class));
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
shellInit.init();
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 18fbf77..6bbac45 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1052,13 +1052,6 @@
}
flag {
- name: "glanceable_hub_gesture_handle"
- namespace: "systemui"
- description: "Shows a vertical bar at the right edge to indicate the user can swipe to open the glanceable hub"
- bug: "339667383"
-}
-
-flag {
name: "glanceable_hub_allow_keyguard_when_dreaming"
namespace: "systemui"
description: "Allows users to exit dream to keyguard with glanceable hub enabled"
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index bb76c1d..cc4e775 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -9,21 +9,14 @@
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.drawBehind
@@ -48,7 +41,6 @@
import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.transitions
import com.android.compose.theme.LocalAndroidColorScheme
-import com.android.systemui.Flags
import com.android.systemui.communal.shared.model.CommunalBackgroundType
import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
@@ -156,8 +148,6 @@
val currentSceneKey: SceneKey by
viewModel.currentScene.collectAsStateWithLifecycle(CommunalScenes.Blank)
val touchesAllowed by viewModel.touchesAllowed.collectAsStateWithLifecycle()
- val showGestureIndicator by
- viewModel.showGestureIndicator.collectAsStateWithLifecycle(initialValue = false)
val backgroundType by
viewModel.communalBackground.collectAsStateWithLifecycle(
initialValue = CommunalBackgroundType.ANIMATED
@@ -200,19 +190,7 @@
)
) {
// This scene shows nothing only allowing for transitions to the communal scene.
- // TODO(b/339667383): remove this temporary swipe gesture handle
- Row(modifier = Modifier.fillMaxSize(), horizontalArrangement = Arrangement.End) {
- if (showGestureIndicator && Flags.glanceableHubGestureHandle()) {
- Box(
- modifier =
- Modifier.height(220.dp)
- .width(4.dp)
- .align(Alignment.CenterVertically)
- .background(color = Color.White, RoundedCornerShape(4.dp))
- )
- Spacer(modifier = Modifier.width(12.dp))
- }
- }
+ Box(modifier = Modifier.fillMaxSize())
}
scene(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index be51c1a..97ed74f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -119,6 +119,7 @@
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.CustomAccessibilityAction
+import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.customActions
import androidx.compose.ui.semantics.onClick
@@ -871,7 +872,7 @@
Icon(
imageVector = Icons.Outlined.Widgets,
contentDescription = stringResource(R.string.cta_label_to_open_widget_picker),
- modifier = Modifier.size(Dimensions.IconSize),
+ modifier = Modifier.size(Dimensions.IconSize).clearAndSetSemantics {},
)
Spacer(modifier = Modifier.size(6.dp))
Text(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index 86a99e0..6412276 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -32,11 +32,9 @@
import android.content.res.Resources;
import android.graphics.Region;
import android.os.Handler;
-import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.testing.TestableLooper.RunWithLooper;
import android.view.AttachedSurfaceControl;
-import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;
@@ -46,7 +44,6 @@
import com.android.dream.lowlight.LowLightTransitionCoordinator;
import com.android.keyguard.BouncerPanelExpansionCalculator;
-import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.ambient.statusbar.ui.AmbientStatusBarViewController;
import com.android.systemui.ambient.touch.scrim.BouncerlessScrimController;
@@ -101,9 +98,6 @@
ViewGroup mDreamOverlayContentView;
@Mock
- View mHubGestureIndicatorView;
-
- @Mock
Handler mHandler;
@Mock
@@ -158,7 +152,6 @@
mDreamOverlayContainerView,
mComplicationHostViewController,
mDreamOverlayContentView,
- mHubGestureIndicatorView,
mAmbientStatusBarViewController,
mLowLightTransitionCoordinator,
mTouchInsetSession,
@@ -179,18 +172,6 @@
mDreamManager);
}
- @DisableFlags(Flags.FLAG_COMMUNAL_HUB)
- @Test
- public void testHubGestureIndicatorGoneWhenFlagOff() {
- verify(mHubGestureIndicatorView, never()).setVisibility(View.VISIBLE);
- }
-
- @EnableFlags({Flags.FLAG_COMMUNAL_HUB, Flags.FLAG_GLANCEABLE_HUB_GESTURE_HANDLE})
- @Test
- public void testHubGestureIndicatorVisibleWhenFlagOn() {
- verify(mHubGestureIndicatorView).setVisibility(View.VISIBLE);
- }
-
@Test
public void testRootSurfaceControlInsetSetOnAttach() {
mController.onViewAttached();
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinatorTest.kt
new file mode 100644
index 0000000..8a9720e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinatorTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import android.app.NotificationChannel
+import android.app.NotificationChannel.NEWS_ID
+import android.app.NotificationChannel.PROMOTIONS_ID
+import android.app.NotificationChannel.RECS_ID
+import android.app.NotificationChannel.SOCIAL_MEDIA_ID
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.render.NodeController
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper
+class BundleCoordinatorTest : SysuiTestCase() {
+ @Mock private lateinit var newsController: NodeController
+ @Mock private lateinit var socialController: NodeController
+ @Mock private lateinit var recsController: NodeController
+ @Mock private lateinit var promoController: NodeController
+
+ private lateinit var coordinator: BundleCoordinator
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ coordinator =
+ BundleCoordinator(
+ newsController,
+ socialController,
+ recsController,
+ promoController
+ )
+ }
+
+ @Test
+ fun newsSectioner() {
+ assertThat(coordinator.newsSectioner.isInSection(makeEntryOfChannelType(NEWS_ID))).isTrue()
+ assertThat(coordinator.newsSectioner.isInSection(makeEntryOfChannelType("news"))).isFalse()
+ }
+
+ @Test
+ fun socialSectioner() {
+ assertThat(coordinator.socialSectioner.isInSection(makeEntryOfChannelType(SOCIAL_MEDIA_ID)))
+ .isTrue()
+ assertThat(coordinator.socialSectioner.isInSection(makeEntryOfChannelType("social")))
+ .isFalse()
+ }
+
+ @Test
+ fun recsSectioner() {
+ assertThat(coordinator.recsSectioner.isInSection(makeEntryOfChannelType(RECS_ID))).isTrue()
+ assertThat(coordinator.recsSectioner.isInSection(makeEntryOfChannelType("recommendations")))
+ .isFalse()
+ }
+
+ @Test
+ fun promoSectioner() {
+ assertThat(coordinator.promoSectioner.isInSection(makeEntryOfChannelType(PROMOTIONS_ID)))
+ .isTrue()
+ assertThat(coordinator.promoSectioner.isInSection(makeEntryOfChannelType("promo"))).
+ isFalse()
+ }
+
+ private fun makeEntryOfChannelType(
+ type: String,
+ buildBlock: NotificationEntryBuilder.() -> Unit = {}
+ ): NotificationEntry {
+ val channel: NotificationChannel = NotificationChannel(type, type, 2)
+ val entry =
+ NotificationEntryBuilder()
+ .updateRanking {
+ it.setChannel(channel)
+ }
+ .also(buildBlock)
+ .build()
+ return entry
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
index 6b5d072..495ab61 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/AvalancheControllerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy
import android.app.Notification
+import android.os.Handler
import android.platform.test.annotations.EnableFlags
import android.testing.TestableLooper.RunWithLooper
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -59,6 +60,9 @@
// For creating TestableHeadsUpManager
@Mock private val mAccessibilityMgr: AccessibilityManagerWrapper? = null
private val mUiEventLoggerFake = UiEventLoggerFake()
+
+ @Mock private lateinit var mBgHandler: Handler
+
private val mLogger = Mockito.spy(HeadsUpManagerLogger(logcatLogBuffer()))
private val mGlobalSettings = FakeGlobalSettings()
private val mSystemClock = FakeSystemClock()
@@ -78,7 +82,7 @@
// Initialize AvalancheController and TestableHeadsUpManager during setUp instead of
// declaration, where mocks are null
- mAvalancheController = AvalancheController(dumpManager, mUiEventLoggerFake)
+ mAvalancheController = AvalancheController(dumpManager, mUiEventLoggerFake, mBgHandler)
testableHeadsUpManager =
TestableHeadsUpManager(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index 206b39c..df07b44 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -38,6 +38,7 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Person;
+import android.os.Handler;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.FlagsParameterization;
@@ -81,7 +82,7 @@
private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
-
+ @Mock private Handler mBgHandler;
@Mock private DumpManager dumpManager;
private AvalancheController mAvalancheController;
@@ -148,7 +149,7 @@
@Override
public void SysuiSetup() throws Exception {
super.SysuiSetup();
- mAvalancheController = new AvalancheController(dumpManager, mUiEventLoggerFake);
+ mAvalancheController = new AvalancheController(dumpManager, mUiEventLoggerFake, mBgHandler);
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
index 7346323..3d3438e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
@@ -104,8 +104,7 @@
UiEventLogger uiEventLogger,
JavaAdapter javaAdapter,
ShadeInteractor shadeInteractor,
- AvalancheController avalancheController,
- Handler bgHandler
+ AvalancheController avalancheController
) {
super(
context,
@@ -123,8 +122,7 @@
uiEventLogger,
javaAdapter,
shadeInteractor,
- avalancheController,
- bgHandler
+ avalancheController
);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
@@ -147,8 +145,7 @@
mUiEventLogger,
mJavaAdapter,
mShadeInteractor,
- mAvalancheController,
- mBgHandler
+ mAvalancheController
);
}
@@ -173,7 +170,7 @@
mContext.getOrCreateTestableResources().addOverride(
R.integer.ambient_notification_extension_time, 500);
- mAvalancheController = new AvalancheController(dumpManager, mUiEventLogger);
+ mAvalancheController = new AvalancheController(dumpManager, mUiEventLogger, mBgHandler);
}
@Test
diff --git a/packages/SystemUI/res/drawable/hub_handle.xml b/packages/SystemUI/res/drawable/hub_handle.xml
deleted file mode 100644
index 8bc276f..0000000
--- a/packages/SystemUI/res/drawable/hub_handle.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ 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.
- -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <corners android:radius="4dp" />
- <solid android:color="#FFFFFF" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/dream_overlay_container.xml b/packages/SystemUI/res/layout/dream_overlay_container.xml
index dcd3fa6..be1652b 100644
--- a/packages/SystemUI/res/layout/dream_overlay_container.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_container.xml
@@ -21,19 +21,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <ImageView
- android:id="@+id/glanceable_hub_handle"
- android:layout_width="4dp"
- android:layout_height="220dp"
- android:layout_centerVertical="true"
- android:layout_marginEnd="12dp"
- android:background="@drawable/hub_handle"
- android:visibility="gone"
- android:contentDescription="UI indicator for swiping open the glanceable hub"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/dream_overlay_content"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index d6d40f2..b466f31 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -995,6 +995,16 @@
}
/**
+ * @return true if ultrasonic udfps HW is supported on this device. Can return true even if
+ * the user has not enrolled udfps. This may be false if called before
+ * onAllAuthenticatorsRegistered.
+ */
+ public boolean isUltrasonicUdfpsSupported() {
+ return getUdfpsProps() != null && !getUdfpsProps().isEmpty() && getUdfpsProps()
+ .get(0).isUltrasonicUdfps();
+ }
+
+ /**
* @return true if sfps HW is supported on this device. Can return true even if the user has
* not enrolled sfps. This may be false if called before onAllAuthenticatorsRegistered.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 9d3c6a4..3dd3758 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -270,6 +270,7 @@
@Override
public void showUdfpsOverlay(long requestId, int sensorId, int reason,
@NonNull IUdfpsOverlayControllerCallback callback) {
+ mUdfpsOverlayInteractor.setRequestId(requestId);
mFgExecutor.execute(() -> UdfpsController.this.showUdfpsOverlay(
new UdfpsControllerOverlay(
mContext,
@@ -404,6 +405,15 @@
handler::post,
authenticationCallback);
}
+
+ /**
+ * Debug to run setIgnoreDisplayTouches
+ */
+ public void debugSetIgnoreDisplayTouches(boolean ignoreTouch) {
+ final long requestId = (mOverlay != null) ? mOverlay.getRequestId() : 0L;
+ UdfpsController.this.mFingerprintManager.setIgnoreDisplayTouches(
+ requestId, mSensorProps.sensorId, ignoreTouch);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
index f5e3d29..97ece11 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
@@ -75,6 +75,8 @@
simFingerUp()
} else if (args.size == 1 && args[0] == "biometricPrompt") {
launchBiometricPrompt()
+ } else if (args.size == 2 && args[0] == "setIgnoreDisplayTouches") {
+ setIgnoreDisplayTouches(args[1].toBoolean())
} else {
invalidCommand(pw)
}
@@ -186,6 +188,11 @@
upEvent?.recycle()
}
+ @VisibleForTesting
+ fun setIgnoreDisplayTouches(ignoreTouches: Boolean) {
+ udfpsOverlayController?.debugSetIgnoreDisplayTouches(ignoreTouches)
+ }
+
private fun obtainMotionEvent(
action: Int,
x: Float,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
index a77cc1f..bb450c0 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractor.kt
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics.domain.interactor
import android.content.Context
+import android.hardware.fingerprint.FingerprintManager
import android.util.Log
import android.view.MotionEvent
import com.android.systemui.biometrics.AuthController
@@ -46,6 +47,7 @@
@Application private val context: Context,
private val authController: AuthController,
private val selectedUserInteractor: SelectedUserInteractor,
+ private val fingerprintManager: FingerprintManager?,
@Application scope: CoroutineScope
) {
private fun calculateIconSize(): Int {
@@ -70,8 +72,25 @@
return isUdfpsEnrolled && isWithinOverlayBounds
}
+ private var _requestId = MutableStateFlow(0L)
+
+ /** RequestId of current AcquisitionClient */
+ val requestId: StateFlow<Long> = _requestId.asStateFlow()
+
+ fun setRequestId(requestId: Long) {
+ _requestId.value = requestId
+ }
+
/** Sets whether Udfps overlay should handle touches */
fun setHandleTouches(shouldHandle: Boolean = true) {
+ if (authController.isUltrasonicUdfpsSupported
+ && shouldHandle != _shouldHandleTouches.value) {
+ fingerprintManager?.setIgnoreDisplayTouches(
+ requestId.value,
+ authController.udfpsProps!!.get(0).sensorId,
+ !shouldHandle
+ )
+ }
_shouldHandleTouches.value = shouldHandle
}
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
index f991d5b..8270db1 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt
@@ -16,7 +16,7 @@
package com.android.systemui.brightness.ui.compose
-import androidx.compose.animation.core.animateIntAsState
+import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
@@ -57,12 +57,12 @@
) {
var value by remember(gammaValue) { mutableIntStateOf(gammaValue) }
val animatedValue by
- animateIntAsState(targetValue = value, label = "BrightnessSliderAnimatedValue")
+ animateFloatAsState(targetValue = value.toFloat(), label = "BrightnessSliderAnimatedValue")
val floatValueRange = valueRange.first.toFloat()..valueRange.last.toFloat()
- val isRestricted = restriction is PolicyRestriction.Restricted
+ val isRestricted = remember(restriction) { restriction is PolicyRestriction.Restricted }
PlatformSlider(
- value = animatedValue.toFloat(),
+ value = animatedValue,
valueRange = floatValueRange,
enabled = !isRestricted,
onValueChange = {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index f9f01f7..780bf70 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -322,14 +322,6 @@
not(shadeInteractor.isAnyFullyExpanded)
.stateIn(bgScope, SharingStarted.Eagerly, initialValue = false)
- // TODO(b/339667383): remove this temporary swipe gesture handle
- /**
- * The dream overlay has its own gesture handle as the SysUI window is not visible above the
- * dream. This flow will be false when dreaming so that we don't show a duplicate handle when
- * opening the hub over the dream.
- */
- val showGestureIndicator: Flow<Boolean> = not(keyguardInteractor.isDreaming)
-
/** The type of background to use for the hub. */
val communalBackground: Flow<CommunalBackgroundType> =
communalSettingsInteractor.communalBackground
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 4fd1c24..76c7d23 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -21,8 +21,6 @@
import static com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress;
import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamAlphaScaledExpansion;
import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamYPositionScaledExpansion;
-import static com.android.systemui.Flags.communalHub;
-import static com.android.systemui.Flags.glanceableHubGestureHandle;
import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_BOTTOM;
import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_TOP;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
@@ -192,7 +190,6 @@
DreamOverlayContainerView containerView,
ComplicationHostViewController complicationHostViewController,
@Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
- @Named(DreamOverlayModule.HUB_GESTURE_INDICATOR_VIEW) View hubGestureIndicatorView,
AmbientStatusBarViewController statusBarViewController,
LowLightTransitionCoordinator lowLightTransitionCoordinator,
TouchInsetManager.TouchInsetSession touchInsetSession,
@@ -230,12 +227,6 @@
mComplicationHostViewController = complicationHostViewController;
mDreamOverlayMaxTranslationY = resources.getDimensionPixelSize(
R.dimen.dream_overlay_y_offset);
-
- if (communalHub() && glanceableHubGestureHandle()) {
- // TODO(b/339667383): remove this temporary swipe gesture handle
- hubGestureIndicatorView.setVisibility(View.VISIBLE);
- }
-
final View view = mComplicationHostViewController.getView();
mDreamOverlayContentView.addView(view,
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
index 76fcabd..12984efb 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -18,7 +18,6 @@
import android.content.res.Resources;
import android.view.LayoutInflater;
-import android.view.View;
import android.view.ViewGroup;
import androidx.lifecycle.Lifecycle;
@@ -42,7 +41,6 @@
@Module
public abstract class DreamOverlayModule {
public static final String DREAM_OVERLAY_CONTENT_VIEW = "dream_overlay_content_view";
- public static final String HUB_GESTURE_INDICATOR_VIEW = "hub_gesture_indicator_view";
public static final String MAX_BURN_IN_OFFSET = "max_burn_in_offset";
public static final String BURN_IN_PROTECTION_UPDATE_INTERVAL =
"burn_in_protection_update_interval";
@@ -75,18 +73,6 @@
"R.id.dream_overlay_content must not be null");
}
- /**
- * Gesture indicator bar on the right edge of the screen to indicate to users that they can
- * swipe to see their widgets on lock screen.
- */
- @Provides
- @DreamOverlayComponent.DreamOverlayScope
- @Named(HUB_GESTURE_INDICATOR_VIEW)
- public static View providesHubGestureIndicatorView(DreamOverlayContainerView view) {
- return Preconditions.checkNotNull(view.findViewById(R.id.glanceable_hub_handle),
- "R.id.glanceable_hub_handle must not be null");
- }
-
/** */
@Provides
public static TouchInsetManager.TouchInsetSession providesTouchInsetSession(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 63dd255..f837d8e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -62,6 +62,7 @@
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/** Defines interface for classes that encapsulate application state for the keyguard. */
interface KeyguardRepository {
@@ -362,30 +363,8 @@
override val topClippingBounds = MutableStateFlow<Int?>(null)
- override val isKeyguardShowing: Flow<Boolean> =
- conflatedCallbackFlow {
- val callback =
- object : KeyguardStateController.Callback {
- override fun onKeyguardShowingChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isShowing,
- TAG,
- "updated isKeyguardShowing"
- )
- }
- }
-
- keyguardStateController.addCallback(callback)
- // Adding the callback does not send an initial update.
- trySendWithFailureLogging(
- keyguardStateController.isShowing,
- TAG,
- "initial isKeyguardShowing"
- )
-
- awaitClose { keyguardStateController.removeCallback(callback) }
- }
- .distinctUntilChanged()
+ override val isKeyguardShowing: MutableStateFlow<Boolean> =
+ MutableStateFlow(keyguardStateController.isShowing)
private val _isAodAvailable = MutableStateFlow(false)
override val isAodAvailable: StateFlow<Boolean> = _isAodAvailable.asStateFlow()
@@ -394,91 +373,14 @@
_isAodAvailable.value = value
}
- override val isKeyguardOccluded: Flow<Boolean> =
- conflatedCallbackFlow {
- val callback =
- object : KeyguardStateController.Callback {
- override fun onKeyguardShowingChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isOccluded,
- TAG,
- "updated isKeyguardOccluded"
- )
- }
- }
+ override val isKeyguardOccluded: MutableStateFlow<Boolean> =
+ MutableStateFlow(keyguardStateController.isOccluded)
- keyguardStateController.addCallback(callback)
- // Adding the callback does not send an initial update.
- trySendWithFailureLogging(
- keyguardStateController.isOccluded,
- TAG,
- "initial isKeyguardOccluded"
- )
+ override val isKeyguardDismissible: MutableStateFlow<Boolean> =
+ MutableStateFlow(keyguardStateController.isUnlocked)
- awaitClose { keyguardStateController.removeCallback(callback) }
- }
- .distinctUntilChanged()
-
- override val isKeyguardDismissible: StateFlow<Boolean> =
- conflatedCallbackFlow {
- val callback =
- object : KeyguardStateController.Callback {
- override fun onUnlockedChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isUnlocked,
- TAG,
- "updated isKeyguardDismissible due to onUnlockedChanged"
- )
- }
-
- override fun onKeyguardShowingChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isUnlocked,
- TAG,
- "updated isKeyguardDismissible due to onKeyguardShowingChanged"
- )
- }
- }
-
- keyguardStateController.addCallback(callback)
- // Adding the callback does not send an initial update.
- trySendWithFailureLogging(
- keyguardStateController.isUnlocked,
- TAG,
- "initial isKeyguardUnlocked"
- )
-
- awaitClose { keyguardStateController.removeCallback(callback) }
- }
- .distinctUntilChanged()
- .stateIn(
- scope,
- SharingStarted.Eagerly,
- initialValue = false,
- )
-
- override val isKeyguardGoingAway: Flow<Boolean> = conflatedCallbackFlow {
- val callback =
- object : KeyguardStateController.Callback {
- override fun onKeyguardGoingAwayChanged() {
- trySendWithFailureLogging(
- keyguardStateController.isKeyguardGoingAway,
- TAG,
- "updated isKeyguardGoingAway"
- )
- }
- }
-
- keyguardStateController.addCallback(callback)
- // Adding the callback does not send an initial update.
- trySendWithFailureLogging(
- keyguardStateController.isKeyguardGoingAway,
- TAG,
- "initial isKeyguardGoingAway"
- )
-
- awaitClose { keyguardStateController.removeCallback(callback) }
- }
+ override val isKeyguardGoingAway: MutableStateFlow<Boolean> =
+ MutableStateFlow(keyguardStateController.isKeyguardGoingAway)
private val _isKeyguardEnabled =
MutableStateFlow(!lockPatternUtils.isLockScreenDisabled(userTracker.userId))
@@ -669,6 +571,35 @@
private val _isActiveDreamLockscreenHosted = MutableStateFlow(false)
override val isActiveDreamLockscreenHosted = _isActiveDreamLockscreenHosted.asStateFlow()
+ init {
+ val callback =
+ object : KeyguardStateController.Callback {
+ override fun onKeyguardShowingChanged() {
+ isKeyguardShowing.value = keyguardStateController.isShowing
+ isKeyguardOccluded.value = keyguardStateController.isOccluded
+ isKeyguardDismissible.value = keyguardStateController.isUnlocked
+ }
+
+ override fun onUnlockedChanged() {
+ isKeyguardDismissible.value = keyguardStateController.isUnlocked
+ }
+
+ override fun onKeyguardGoingAwayChanged() {
+ isKeyguardGoingAway.value = keyguardStateController.isKeyguardGoingAway
+ }
+ }
+
+ keyguardStateController.addCallback(callback)
+
+ scope
+ .launch {
+ isKeyguardShowing.collect {
+ // no-op to allow for callback removal
+ }
+ }
+ .invokeOnCompletion { keyguardStateController.removeCallback(callback) }
+ }
+
override fun setAnimateDozingTransitions(animate: Boolean) {
_animateBottomAreaDozingTransitions.value = animate
}
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 22ab82b..ab1194e 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
@@ -51,6 +51,7 @@
import com.android.systemui.statusbar.notification.NotificationUtils.interpolate
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
+import com.android.systemui.util.kotlin.Utils.Companion.sampleFilter
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
@@ -250,17 +251,13 @@
/** Keyguard can be clipped at the top as the shade is dragged */
val topClippingBounds: Flow<Int?> by lazy {
- combineTransform(
+ repository.topClippingBounds
+ .sampleFilter(
keyguardTransitionInteractor
.transitionValue(scene = Scenes.Gone, stateWithoutSceneContainer = GONE)
- .map { it == 1f }
- .onStart { emit(false) }
- .distinctUntilChanged(),
- repository.topClippingBounds
- ) { isGone, topClippingBounds ->
- if (!isGone) {
- emit(topClippingBounds)
- }
+ .onStart { emit(0f) }
+ ) { goneValue ->
+ goneValue != 1f
}
.distinctUntilChanged()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index 1c7b4d9..76f7749 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -38,7 +38,9 @@
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.res.R
import com.android.systemui.statusbar.VibratorHelper
+import com.android.systemui.util.kotlin.DisposableHandles
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
@@ -64,8 +66,9 @@
falsingManager: FalsingManager,
vibratorHelper: VibratorHelper,
overrideColor: Color? = null,
- ) {
+ ): DisposableHandle {
DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()
+ val disposables = DisposableHandles()
val longPressHandlingView = view.longPressHandlingView
val fgIconView = view.iconView
val bgView = view.bgView
@@ -83,118 +86,125 @@
}
}
- view.repeatWhenAttached {
- // Repeat on CREATED so that the view will always observe the entire
- // GONE => AOD transition (even though the view may not be visible until the middle
- // of the transition.
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch("$TAG#viewModel.isVisible") {
- viewModel.isVisible.collect { isVisible ->
- longPressHandlingView.isInvisible = !isVisible
+ disposables +=
+ view.repeatWhenAttached {
+ // Repeat on CREATED so that the view will always observe the entire
+ // GONE => AOD transition (even though the view may not be visible until the middle
+ // of the transition.
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ launch("$TAG#viewModel.isVisible") {
+ viewModel.isVisible.collect { isVisible ->
+ longPressHandlingView.isInvisible = !isVisible
+ }
}
- }
- launch("$TAG#viewModel.isLongPressEnabled") {
- viewModel.isLongPressEnabled.collect { isEnabled ->
- longPressHandlingView.setLongPressHandlingEnabled(isEnabled)
+ launch("$TAG#viewModel.isLongPressEnabled") {
+ viewModel.isLongPressEnabled.collect { isEnabled ->
+ longPressHandlingView.setLongPressHandlingEnabled(isEnabled)
+ }
}
- }
- launch("$TAG#viewModel.isUdfpsSupported") {
- viewModel.isUdfpsSupported.collect { udfpsSupported ->
- longPressHandlingView.longPressDuration =
- if (udfpsSupported) {
- {
- view.resources
- .getInteger(R.integer.config_udfpsDeviceEntryIconLongPress)
- .toLong()
+ launch("$TAG#viewModel.isUdfpsSupported") {
+ viewModel.isUdfpsSupported.collect { udfpsSupported ->
+ longPressHandlingView.longPressDuration =
+ if (udfpsSupported) {
+ {
+ view.resources
+ .getInteger(
+ R.integer.config_udfpsDeviceEntryIconLongPress
+ )
+ .toLong()
+ }
+ } else {
+ {
+ view.resources
+ .getInteger(R.integer.config_lockIconLongPress)
+ .toLong()
+ }
+ }
+ }
+ }
+ launch("$TAG#viewModel.accessibilityDelegateHint") {
+ viewModel.accessibilityDelegateHint.collect { hint ->
+ view.accessibilityHintType = hint
+ if (hint != DeviceEntryIconView.AccessibilityHintType.NONE) {
+ view.setOnClickListener {
+ vibratorHelper.performHapticFeedback(
+ view,
+ HapticFeedbackConstants.CONFIRM,
+ )
+ applicationScope.launch { viewModel.onUserInteraction() }
}
} else {
- {
- view.resources
- .getInteger(R.integer.config_lockIconLongPress)
- .toLong()
- }
+ view.setOnClickListener(null)
}
+ }
}
- }
- launch("$TAG#viewModel.accessibilityDelegateHint") {
- viewModel.accessibilityDelegateHint.collect { hint ->
- view.accessibilityHintType = hint
- if (hint != DeviceEntryIconView.AccessibilityHintType.NONE) {
- view.setOnClickListener {
- vibratorHelper.performHapticFeedback(
- view,
- HapticFeedbackConstants.CONFIRM,
- )
- applicationScope.launch { viewModel.onUserInteraction() }
+ launch("$TAG#viewModel.useBackgroundProtection") {
+ viewModel.useBackgroundProtection.collect { useBackgroundProtection ->
+ if (useBackgroundProtection) {
+ bgView.visibility = View.VISIBLE
+ } else {
+ bgView.visibility = View.GONE
}
- } else {
- view.setOnClickListener(null)
}
}
- }
- launch("$TAG#viewModel.useBackgroundProtection") {
- viewModel.useBackgroundProtection.collect { useBackgroundProtection ->
- if (useBackgroundProtection) {
- bgView.visibility = View.VISIBLE
- } else {
- bgView.visibility = View.GONE
+ launch("$TAG#viewModel.burnInOffsets") {
+ viewModel.burnInOffsets.collect { burnInOffsets ->
+ view.translationX = burnInOffsets.x.toFloat()
+ view.translationY = burnInOffsets.y.toFloat()
+ view.aodFpDrawable.progress = burnInOffsets.progress
}
}
- }
- launch("$TAG#viewModel.burnInOffsets") {
- viewModel.burnInOffsets.collect { burnInOffsets ->
- view.translationX = burnInOffsets.x.toFloat()
- view.translationY = burnInOffsets.y.toFloat()
- view.aodFpDrawable.progress = burnInOffsets.progress
- }
- }
- launch("$TAG#viewModel.deviceEntryViewAlpha") {
- viewModel.deviceEntryViewAlpha.collect { alpha -> view.alpha = alpha }
- }
- }
- }
-
- fgIconView.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- // Start with an empty state
- fgIconView.setImageState(StateSet.NOTHING, /* merge */ false)
- launch("$TAG#fpIconView.viewModel") {
- fgViewModel.viewModel.collect { viewModel ->
- fgIconView.setImageState(
- view.getIconState(viewModel.type, viewModel.useAodVariant),
- /* merge */ false
- )
- if (viewModel.type.contentDescriptionResId != -1) {
- fgIconView.contentDescription =
- fgIconView.resources.getString(
- viewModel.type.contentDescriptionResId
- )
- }
- fgIconView.imageTintList =
- ColorStateList.valueOf(overrideColor?.toArgb() ?: viewModel.tint)
- fgIconView.setPadding(
- viewModel.padding,
- viewModel.padding,
- viewModel.padding,
- viewModel.padding,
- )
+ launch("$TAG#viewModel.deviceEntryViewAlpha") {
+ viewModel.deviceEntryViewAlpha.collect { alpha -> view.alpha = alpha }
}
}
}
- }
- bgView.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch("$TAG#bgViewModel.alpha") {
- bgViewModel.alpha.collect { alpha -> bgView.alpha = alpha }
- }
- launch("$TAG#bgViewModel.color") {
- bgViewModel.color.collect { color ->
- bgView.imageTintList = ColorStateList.valueOf(color)
+ disposables +=
+ fgIconView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ // Start with an empty state
+ fgIconView.setImageState(StateSet.NOTHING, /* merge */ false)
+ launch("$TAG#fpIconView.viewModel") {
+ fgViewModel.viewModel.collect { viewModel ->
+ fgIconView.setImageState(
+ view.getIconState(viewModel.type, viewModel.useAodVariant),
+ /* merge */ false
+ )
+ if (viewModel.type.contentDescriptionResId != -1) {
+ fgIconView.contentDescription =
+ fgIconView.resources.getString(
+ viewModel.type.contentDescriptionResId
+ )
+ }
+ fgIconView.imageTintList =
+ ColorStateList.valueOf(overrideColor?.toArgb() ?: viewModel.tint)
+ fgIconView.setPadding(
+ viewModel.padding,
+ viewModel.padding,
+ viewModel.padding,
+ viewModel.padding,
+ )
+ }
}
}
}
- }
+
+ disposables +=
+ bgView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ launch("$TAG#bgViewModel.alpha") {
+ bgViewModel.alpha.collect { alpha -> bgView.alpha = alpha }
+ }
+ launch("$TAG#bgViewModel.color") {
+ bgViewModel.color.collect { color ->
+ bgView.imageTintList = ColorStateList.valueOf(color)
+ }
+ }
+ }
+ }
+
+ return disposables
}
}
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 e063380..ba9f018 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,7 +37,9 @@
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.kotlin.DisposableHandles
import com.android.systemui.util.ui.value
+import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
@@ -56,85 +58,94 @@
keyguardClockInteractor: KeyguardClockInteractor,
blueprintInteractor: KeyguardBlueprintInteractor,
rootViewModel: KeyguardRootViewModel,
- ) {
- keyguardRootView.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- keyguardClockInteractor.clockEventController.registerListeners(keyguardRootView)
+ ): DisposableHandle {
+ val disposables = DisposableHandles()
+ disposables +=
+ keyguardRootView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ keyguardClockInteractor.clockEventController.registerListeners(keyguardRootView)
+ }
}
- }
- keyguardRootView.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch {
- if (!MigrateClocksToBlueprint.isEnabled) return@launch
- viewModel.currentClock.collect { currentClock ->
- cleanupClockViews(currentClock, keyguardRootView, viewModel.burnInLayer)
- addClockViews(currentClock, keyguardRootView)
- updateBurnInLayer(keyguardRootView, viewModel, viewModel.clockSize.value)
- applyConstraints(clockSection, keyguardRootView, true)
- }
- }
-
- launch {
- if (!MigrateClocksToBlueprint.isEnabled) return@launch
- viewModel.clockSize.collect { clockSize ->
- updateBurnInLayer(keyguardRootView, viewModel, clockSize)
- blueprintInteractor.refreshBlueprint(Type.ClockSize)
- }
- }
-
- launch {
- if (!MigrateClocksToBlueprint.isEnabled) return@launch
- viewModel.clockShouldBeCentered.collect {
- viewModel.currentClock.value?.let {
- // TODO(b/301502635): remove "!it.config.useCustomClockScene" when
- // migrate clocks to blueprint is fully rolled out
- if (
- it.largeClock.config.hasCustomPositionUpdatedAnimation &&
- !it.config.useCustomClockScene
- ) {
- blueprintInteractor.refreshBlueprint(Type.DefaultClockStepping)
- } else {
- blueprintInteractor.refreshBlueprint(Type.DefaultTransition)
- }
+ disposables +=
+ keyguardRootView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ launch {
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
+ viewModel.currentClock.collect { currentClock ->
+ cleanupClockViews(currentClock, keyguardRootView, viewModel.burnInLayer)
+ addClockViews(currentClock, keyguardRootView)
+ updateBurnInLayer(
+ keyguardRootView,
+ viewModel,
+ viewModel.clockSize.value
+ )
+ applyConstraints(clockSection, keyguardRootView, true)
}
}
- }
- launch {
- if (!MigrateClocksToBlueprint.isEnabled) return@launch
- combine(
- viewModel.hasAodIcons,
- rootViewModel.isNotifIconContainerVisible.map { it.value }
- ) { hasIcon, isVisible ->
- hasIcon && isVisible
+ launch {
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
+ viewModel.clockSize.collect { clockSize ->
+ updateBurnInLayer(keyguardRootView, viewModel, clockSize)
+ blueprintInteractor.refreshBlueprint(Type.ClockSize)
}
- .distinctUntilChanged()
- .collect { _ ->
+ }
+
+ launch {
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
+ viewModel.clockShouldBeCentered.collect {
viewModel.currentClock.value?.let {
- if (it.config.useCustomClockScene) {
+ // TODO(b/301502635): remove "!it.config.useCustomClockScene" when
+ // migrate clocks to blueprint is fully rolled out
+ if (
+ it.largeClock.config.hasCustomPositionUpdatedAnimation &&
+ !it.config.useCustomClockScene
+ ) {
+ blueprintInteractor.refreshBlueprint(Type.DefaultClockStepping)
+ } else {
blueprintInteractor.refreshBlueprint(Type.DefaultTransition)
}
}
}
- }
+ }
- launch {
- if (!MigrateClocksToBlueprint.isEnabled) return@launch
- rootViewModel.burnInModel.collect { burnInModel ->
- viewModel.currentClock.value?.let {
- it.largeClock.layout.applyAodBurnIn(
- AodClockBurnInModel(
- translationX = burnInModel.translationX.toFloat(),
- translationY = burnInModel.translationY.toFloat(),
- scale = burnInModel.scale
+ launch {
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
+ 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 {
+ if (!MigrateClocksToBlueprint.isEnabled) return@launch
+ rootViewModel.burnInModel.collect { burnInModel ->
+ viewModel.currentClock.value?.let {
+ it.largeClock.layout.applyAodBurnIn(
+ AodClockBurnInModel(
+ translationX = burnInModel.translationX.toFloat(),
+ translationY = burnInModel.translationY.toFloat(),
+ scale = burnInModel.scale
+ )
)
- )
+ }
}
}
}
}
- }
+
+ return disposables
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index fc92afe..8f149fb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -267,6 +267,23 @@
}
}
+ launch {
+ blueprintViewModel.currentTransition.collect { currentTransition ->
+ // When blueprint/clock transitions end (null), make sure NSSL is in
+ // the right place
+ if (currentTransition == null) {
+ childViews[nsslPlaceholderId]?.let { notificationListPlaceholder
+ ->
+ viewModel.onNotificationContainerBoundsChanged(
+ notificationListPlaceholder.top.toFloat(),
+ notificationListPlaceholder.bottom.toFloat(),
+ animate = true,
+ )
+ }
+ }
+ }
+ }
+
if (NotificationIconContainerRefactor.isEnabled) {
launch {
val iconsAppearTranslationPx =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
index 191056c..8b74f5d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardSmartspaceViewBinder.kt
@@ -31,6 +31,7 @@
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import com.android.systemui.shared.R as sharedR
+import kotlinx.coroutines.DisposableHandle
object KeyguardSmartspaceViewBinder {
@JvmStatic
@@ -39,8 +40,8 @@
clockViewModel: KeyguardClockViewModel,
smartspaceViewModel: KeyguardSmartspaceViewModel,
blueprintInteractor: KeyguardBlueprintInteractor,
- ) {
- keyguardRootView.repeatWhenAttached {
+ ): DisposableHandle {
+ return keyguardRootView.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
launch("$TAG#clockViewModel.hasCustomWeatherDataDisplay") {
if (!MigrateClocksToBlueprint.isEnabled) return@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 0637bba..91e48b5 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
@@ -48,6 +48,7 @@
import com.android.systemui.util.ui.value
import dagger.Lazy
import javax.inject.Inject
+import kotlinx.coroutines.DisposableHandle
internal fun ConstraintSet.setVisibility(
views: Iterable<View>,
@@ -70,21 +71,24 @@
val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>,
private val rootViewModel: KeyguardRootViewModel,
) : KeyguardSection() {
+ private var disposableHandle: DisposableHandle? = null
+
override fun addViews(constraintLayout: ConstraintLayout) {}
override fun bindData(constraintLayout: ConstraintLayout) {
if (!MigrateClocksToBlueprint.isEnabled) {
return
}
-
- KeyguardClockViewBinder.bind(
- this,
- constraintLayout,
- keyguardClockViewModel,
- clockInteractor,
- blueprintInteractor.get(),
- rootViewModel,
- )
+ disposableHandle?.dispose()
+ disposableHandle =
+ KeyguardClockViewBinder.bind(
+ this,
+ constraintLayout,
+ keyguardClockViewModel,
+ clockInteractor,
+ blueprintInteractor.get(),
+ rootViewModel,
+ )
}
override fun applyConstraints(constraintSet: ConstraintSet) {
@@ -97,7 +101,13 @@
}
}
- override fun removeViews(constraintLayout: ConstraintLayout) {}
+ override fun removeViews(constraintLayout: ConstraintLayout) {
+ if (!MigrateClocksToBlueprint.isEnabled) {
+ return
+ }
+
+ disposableHandle?.dispose()
+ }
private fun buildConstraints(
clock: ClockController,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
index e01f0a1..51230dd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntrySection.kt
@@ -49,6 +49,7 @@
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.ExperimentalCoroutinesApi
/** Includes the device entry icon. */
@@ -70,6 +71,7 @@
private val vibratorHelper: Lazy<VibratorHelper>,
) : KeyguardSection() {
private val deviceEntryIconViewId = R.id.device_entry_icon_view
+ private var disposableHandle: DisposableHandle? = null
override fun addViews(constraintLayout: ConstraintLayout) {
if (
@@ -97,15 +99,17 @@
override fun bindData(constraintLayout: ConstraintLayout) {
if (DeviceEntryUdfpsRefactor.isEnabled) {
constraintLayout.findViewById<DeviceEntryIconView?>(deviceEntryIconViewId)?.let {
- DeviceEntryIconViewBinder.bind(
- applicationScope,
- it,
- deviceEntryIconViewModel.get(),
- deviceEntryForegroundViewModel.get(),
- deviceEntryBackgroundViewModel.get(),
- falsingManager.get(),
- vibratorHelper.get(),
- )
+ disposableHandle?.dispose()
+ disposableHandle =
+ DeviceEntryIconViewBinder.bind(
+ applicationScope,
+ it,
+ deviceEntryIconViewModel.get(),
+ deviceEntryForegroundViewModel.get(),
+ deviceEntryBackgroundViewModel.get(),
+ falsingManager.get(),
+ vibratorHelper.get(),
+ )
}
} else {
constraintLayout.findViewById<LockIconView?>(R.id.lock_icon_view)?.let {
@@ -178,6 +182,7 @@
override fun removeViews(constraintLayout: ConstraintLayout) {
if (DeviceEntryUdfpsRefactor.isEnabled) {
constraintLayout.removeView(deviceEntryIconViewId)
+ disposableHandle?.dispose()
} else {
constraintLayout.removeView(R.id.lock_icon_view)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
index 8a751f0..55fc718 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SmartspaceSection.kt
@@ -37,6 +37,7 @@
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
import dagger.Lazy
import javax.inject.Inject
+import kotlinx.coroutines.DisposableHandle
@SysUISingleton
open class SmartspaceSection
@@ -56,6 +57,7 @@
private var smartspaceVisibilityListener: OnGlobalLayoutListener? = null
private var pastVisibility: Int = -1
+ private var disposableHandle: DisposableHandle? = null
override fun onRebuildBegin() {
smartspaceController.suppressDisconnects = true
@@ -96,12 +98,14 @@
override fun bindData(constraintLayout: ConstraintLayout) {
if (!MigrateClocksToBlueprint.isEnabled) return
if (!keyguardSmartspaceViewModel.isSmartspaceEnabled) return
- KeyguardSmartspaceViewBinder.bind(
- constraintLayout,
- keyguardClockViewModel,
- keyguardSmartspaceViewModel,
- blueprintInteractor.get(),
- )
+ disposableHandle?.dispose()
+ disposableHandle =
+ KeyguardSmartspaceViewBinder.bind(
+ constraintLayout,
+ keyguardClockViewModel,
+ keyguardSmartspaceViewModel,
+ blueprintInteractor.get(),
+ )
}
override fun applyConstraints(constraintSet: ConstraintSet) {
@@ -188,6 +192,8 @@
}
smartspaceView?.viewTreeObserver?.removeOnGlobalLayoutListener(smartspaceVisibilityListener)
smartspaceVisibilityListener = null
+
+ disposableHandle?.dispose()
}
private fun updateVisibility(constraintSet: ConstraintSet) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 988fe64..18a04ec 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -158,7 +158,7 @@
}
if (mp != null) {
if (DEBUG) {
- Log.d(mTag, "mPlayer.pause+release piid:" + player.getPlayerIId());
+ Log.d(mTag, "mp.pause+release piid:" + mp.getPlayerIId());
}
mp.pause();
try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
index f62b24a..3dcaff3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
@@ -21,6 +21,7 @@
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.NotificationClassificationFlag
import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype
import com.android.systemui.statusbar.notification.shared.PriorityPeopleSection
import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
@@ -51,7 +52,8 @@
}
fun getNotificationBuckets(): IntArray {
- if (PriorityPeopleSection.isEnabled || NotificationMinimalismPrototype.V2.isEnabled) {
+ if (PriorityPeopleSection.isEnabled || NotificationMinimalismPrototype.V2.isEnabled
+ || NotificationClassificationFlag.isEnabled) {
// We don't need this list to be adaptive, it can be the superset of all features.
return PriorityBucket.getAllInOrder()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationClassificationFlag.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationClassificationFlag.kt
new file mode 100644
index 0000000..139347c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationClassificationFlag.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.notification.collection
+
+import android.service.notification.Flags
+import com.android.systemui.flags.FlagToken
+import com.android.systemui.flags.RefactorFlagUtils
+
+/**
+ * Helper for android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION
+ */
+@Suppress("NOTHING_TO_INLINE")
+object NotificationClassificationFlag {
+ const val FLAG_NAME = Flags.FLAG_NOTIFICATION_CLASSIFICATION
+
+ /** A token used for dependency declaration */
+ val token: FlagToken
+ get() = FlagToken(FLAG_NAME, isEnabled)
+
+ /** Are sections sorted by time? */
+ @JvmStatic
+ inline val isEnabled
+ get() = Flags.notificationClassification()
+
+ /**
+ * Called to ensure code is only run when the flag is enabled. This protects users from the
+ * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
+ * build to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun isUnexpectedlyInLegacyMode() =
+ RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
+
+ /**
+ * Called to ensure code is only run when the flag is disabled. This will throw an exception if
+ * the flag is enabled to ensure that the refactor author catches issues in testing.
+ */
+ @JvmStatic
+ inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinator.kt
new file mode 100644
index 0000000..244c594
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BundleCoordinator.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import android.app.NotificationChannel.NEWS_ID
+import android.app.NotificationChannel.PROMOTIONS_ID
+import android.app.NotificationChannel.RECS_ID
+import android.app.NotificationChannel.SOCIAL_MEDIA_ID
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
+import com.android.systemui.statusbar.notification.collection.render.NodeController
+import com.android.systemui.statusbar.notification.dagger.NewsHeader
+import com.android.systemui.statusbar.notification.dagger.PromoHeader
+import com.android.systemui.statusbar.notification.dagger.RecsHeader
+import com.android.systemui.statusbar.notification.dagger.SocialHeader
+import com.android.systemui.statusbar.notification.stack.BUCKET_NEWS
+import com.android.systemui.statusbar.notification.stack.BUCKET_PROMO
+import com.android.systemui.statusbar.notification.stack.BUCKET_RECS
+import com.android.systemui.statusbar.notification.stack.BUCKET_SOCIAL
+import javax.inject.Inject
+
+/**
+ * Coordinator for sections derived from NotificationAssistantService classification.
+ */
+@CoordinatorScope
+class BundleCoordinator @Inject constructor(
+ @NewsHeader private val newsHeaderController: NodeController,
+ @SocialHeader private val socialHeaderController: NodeController,
+ @RecsHeader private val recsHeaderController: NodeController,
+ @PromoHeader private val promoHeaderController: NodeController,
+) : Coordinator {
+
+ val newsSectioner =
+ object : NotifSectioner("News", BUCKET_NEWS) {
+ override fun isInSection(entry: ListEntry): Boolean {
+ return entry.representativeEntry?.channel?.id == NEWS_ID
+ }
+
+ override fun getHeaderNodeController(): NodeController? {
+ return newsHeaderController
+ }
+ }
+
+ val socialSectioner =
+ object : NotifSectioner("Social", BUCKET_SOCIAL) {
+ override fun isInSection(entry: ListEntry): Boolean {
+ return entry.representativeEntry?.channel?.id == SOCIAL_MEDIA_ID
+ }
+
+ override fun getHeaderNodeController(): NodeController? {
+ return socialHeaderController
+ }
+ }
+
+ val recsSectioner =
+ object : NotifSectioner("Recommendations", BUCKET_RECS) {
+ override fun isInSection(entry: ListEntry): Boolean {
+ return entry.representativeEntry?.channel?.id == RECS_ID
+ }
+
+ override fun getHeaderNodeController(): NodeController? {
+ return recsHeaderController
+ }
+ }
+
+ val promoSectioner =
+ object : NotifSectioner("Promotions", BUCKET_PROMO) {
+ override fun isInSection(entry: ListEntry): Boolean {
+ return entry.representativeEntry?.channel?.id == PROMOTIONS_ID
+ }
+
+ override fun getHeaderNodeController(): NodeController? {
+ return promoHeaderController
+ }
+ }
+
+ override fun attach(pipeline: NotifPipeline) {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index e413522..e038982 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -17,10 +17,7 @@
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED
-import com.android.systemui.statusbar.notification.collection.NotifPipeline
-import com.android.systemui.statusbar.notification.collection.PipelineDumpable
-import com.android.systemui.statusbar.notification.collection.PipelineDumper
-import com.android.systemui.statusbar.notification.collection.SortBySectionTimeFlag
+import com.android.systemui.statusbar.notification.collection.*
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider
@@ -69,6 +66,7 @@
dismissibilityCoordinator: DismissibilityCoordinator,
dreamCoordinator: DreamCoordinator,
statsLoggerCoordinator: NotificationStatsLoggerCoordinator,
+ bundleCoordinator: BundleCoordinator,
) : NotifCoordinators {
private val mCoreCoordinators: MutableList<CoreCoordinator> = ArrayList()
@@ -132,6 +130,12 @@
mOrderedSections.add(conversationCoordinator.peopleSilentSectioner) // People Silent
}
mOrderedSections.add(rankingCoordinator.alertingSectioner) // Alerting
+ if (NotificationClassificationFlag.isEnabled) {
+ mOrderedSections.add(bundleCoordinator.newsSectioner);
+ mOrderedSections.add(bundleCoordinator.socialSectioner);
+ mOrderedSections.add(bundleCoordinator.recsSectioner);
+ mOrderedSections.add(bundleCoordinator.promoSectioner);
+ }
mOrderedSections.add(rankingCoordinator.silentSectioner) // Silent
mOrderedSections.add(rankingCoordinator.minimizedSectioner) // Minimized
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt
index ca43591..e661090 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt
@@ -80,6 +80,50 @@
.build()
@Provides
+ @NewsHeader
+ @SysUISingleton
+ @JvmStatic fun providesNewsHeaderSubcomponent(
+ builder: Provider<SectionHeaderControllerSubcomponent.Builder>
+ ) = builder.get()
+ .nodeLabel("news header")
+ .headerText(com.android.internal.R.string.news_notification_channel_label)
+ .clickIntentAction(Settings.ACTION_NOTIFICATION_SETTINGS)
+ .build()
+
+ @Provides
+ @SocialHeader
+ @SysUISingleton
+ @JvmStatic fun providesSocialHeaderSubcomponent(
+ builder: Provider<SectionHeaderControllerSubcomponent.Builder>
+ ) = builder.get()
+ .nodeLabel("social header")
+ .headerText(com.android.internal.R.string.social_notification_channel_label)
+ .clickIntentAction(Settings.ACTION_NOTIFICATION_SETTINGS)
+ .build()
+
+ @Provides
+ @RecsHeader
+ @SysUISingleton
+ @JvmStatic fun providesRecsHeaderSubcomponent(
+ builder: Provider<SectionHeaderControllerSubcomponent.Builder>
+ ) = builder.get()
+ .nodeLabel("recs header")
+ .headerText(com.android.internal.R.string.recs_notification_channel_label)
+ .clickIntentAction(Settings.ACTION_NOTIFICATION_SETTINGS)
+ .build()
+
+ @Provides
+ @PromoHeader
+ @SysUISingleton
+ @JvmStatic fun providesPromoHeaderSubcomponent(
+ builder: Provider<SectionHeaderControllerSubcomponent.Builder>
+ ) = builder.get()
+ .nodeLabel("promo header")
+ .headerText(com.android.internal.R.string.promotional_notification_channel_label)
+ .clickIntentAction(Settings.ACTION_NOTIFICATION_SETTINGS)
+ .build()
+
+ @Provides
@SilentHeader
@JvmStatic fun providesSilentHeaderNodeController(
@SilentHeader subcomponent: SectionHeaderControllerSubcomponent
@@ -126,6 +170,54 @@
@JvmStatic fun providesIncomingHeaderController(
@IncomingHeader subcomponent: SectionHeaderControllerSubcomponent
) = subcomponent.headerController
+
+ @Provides
+ @NewsHeader
+ @JvmStatic fun providesNewsHeaderNodeController(
+ @NewsHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.nodeController
+
+ @Provides
+ @NewsHeader
+ @JvmStatic fun providesNewsHeaderController(
+ @NewsHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.headerController
+
+ @Provides
+ @SocialHeader
+ @JvmStatic fun providesSocialHeaderNodeController(
+ @SocialHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.nodeController
+
+ @Provides
+ @SocialHeader
+ @JvmStatic fun providesSocialHeaderController(
+ @SocialHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.headerController
+
+ @Provides
+ @RecsHeader
+ @JvmStatic fun providesRecsHeaderNodeController(
+ @RecsHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.nodeController
+
+ @Provides
+ @RecsHeader
+ @JvmStatic fun providesRecsHeaderController(
+ @RecsHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.headerController
+
+ @Provides
+ @PromoHeader
+ @JvmStatic fun providesPromoHeaderNodeController(
+ @PromoHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.nodeController
+
+ @Provides
+ @PromoHeader
+ @JvmStatic fun providesPromoHeaderController(
+ @PromoHeader subcomponent: SectionHeaderControllerSubcomponent
+ ) = subcomponent.headerController
}
@Subcomponent(modules = [ SectionHeaderBindingModule::class ])
@@ -183,3 +275,19 @@
@Scope
@Retention(AnnotationRetention.BINARY)
annotation class SectionHeaderScope
+
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class NewsHeader
+
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class SocialHeader
+
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class RecsHeader
+
+@Qualifier
+@Retention(AnnotationRetention.BINARY)
+annotation class PromoHeader
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
index 9e0dd8fc..1755123 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -20,9 +20,13 @@
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_FOREGROUND_SERVICE;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_HEADS_UP;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_NEWS;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PRIORITY_PEOPLE;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PROMO;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_RECS;
import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
+import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SOCIAL;
import android.annotation.Nullable;
import android.service.notification.StatusBarNotification;
@@ -135,6 +139,10 @@
return Notifications.Notification.SECTION_PEOPLE;
case BUCKET_ALERTING: return Notifications.Notification.SECTION_ALERTING;
case BUCKET_SILENT: return Notifications.Notification.SECTION_SILENT;
+ case BUCKET_NEWS: return Notifications.Notification.SECTION_NEWS;
+ case BUCKET_SOCIAL: return Notifications.Notification.SECTION_SOCIAL;
+ case BUCKET_RECS: return Notifications.Notification.SECTION_RECS;
+ case BUCKET_PROMO: return Notifications.Notification.SECTION_PROMO;
}
return Notifications.Notification.SECTION_UNKNOWN;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
index c2ab275..ce4356a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
@@ -43,6 +43,13 @@
SECTION_ALERTING = 4;
SECTION_SILENT = 5;
SECTION_FOREGROUND_SERVICE = 6;
+ SECTION_PRIORITY_PEOPLE = 7;
+ SECTION_TOP_ONGOING = 8;
+ SECTION_TOP_UNSEEN = 9;
+ SECTION_NEWS = 10;
+ SECTION_SOCIAL = 11;
+ SECTION_RECS = 12;
+ SECTION_PROMO = 13;
}
optional NotificationSection section = 6;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
index fabb696..f4a4527 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
@@ -20,6 +20,10 @@
BUCKET_PRIORITY_PEOPLE,
BUCKET_PEOPLE,
BUCKET_ALERTING,
+ BUCKET_NEWS,
+ BUCKET_SOCIAL,
+ BUCKET_RECS,
+ BUCKET_PROMO,
BUCKET_SILENT
]
)
@@ -35,6 +39,10 @@
BUCKET_PRIORITY_PEOPLE,
BUCKET_PEOPLE,
BUCKET_ALERTING,
+ BUCKET_NEWS,
+ BUCKET_SOCIAL,
+ BUCKET_RECS,
+ BUCKET_PROMO,
BUCKET_SILENT,
)
}
@@ -49,4 +57,9 @@
const val BUCKET_PRIORITY_PEOPLE = 7
const val BUCKET_PEOPLE = 4
const val BUCKET_ALERTING = 5
+const val BUCKET_NEWS = 10
+const val BUCKET_SOCIAL = 11
+const val BUCKET_RECS = 12
+const val BUCKET_PROMO = 13
const val BUCKET_SILENT = 6
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 3400ad1..7441c70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -22,12 +22,10 @@
import com.android.systemui.media.controls.ui.controller.KeyguardMediaController
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
import com.android.systemui.statusbar.notification.SourceType
+import com.android.systemui.statusbar.notification.collection.NotificationClassificationFlag
import com.android.systemui.statusbar.notification.collection.render.MediaContainerController
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController
-import com.android.systemui.statusbar.notification.dagger.AlertingHeader
-import com.android.systemui.statusbar.notification.dagger.IncomingHeader
-import com.android.systemui.statusbar.notification.dagger.PeopleHeader
-import com.android.systemui.statusbar.notification.dagger.SilentHeader
+import com.android.systemui.statusbar.notification.dagger.*
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
@@ -51,7 +49,11 @@
@IncomingHeader private val incomingHeaderController: SectionHeaderController,
@PeopleHeader private val peopleHeaderController: SectionHeaderController,
@AlertingHeader private val alertingHeaderController: SectionHeaderController,
- @SilentHeader private val silentHeaderController: SectionHeaderController
+ @SilentHeader private val silentHeaderController: SectionHeaderController,
+ @NewsHeader private val newsHeaderController: SectionHeaderController,
+ @SocialHeader private val socialHeaderController: SectionHeaderController,
+ @RecsHeader private val recsHeaderController: SectionHeaderController,
+ @PromoHeader private val promoHeaderController: SectionHeaderController
) : SectionProvider {
private val configurationListener =
@@ -84,6 +86,22 @@
val mediaControlsView: MediaContainerView?
get() = mediaContainerController.mediaContainerView
+ @VisibleForTesting
+ val newsHeaderView: SectionHeaderView?
+ get() = newsHeaderController.headerView
+
+ @VisibleForTesting
+ val socialHeaderView: SectionHeaderView?
+ get() = socialHeaderController.headerView
+
+ @VisibleForTesting
+ val recsHeaderView: SectionHeaderView?
+ get() = recsHeaderController.headerView
+
+ @VisibleForTesting
+ val promoHeaderView: SectionHeaderView?
+ get() = promoHeaderController.headerView
+
/** Must be called before use. */
fun initialize(parent: NotificationStackScrollLayout) {
check(!initialized) { "NotificationSectionsManager already initialized" }
@@ -107,15 +125,24 @@
incomingHeaderController.reinflateView(parent)
mediaContainerController.reinflateView(parent)
keyguardMediaController.attachSinglePaneContainer(mediaControlsView)
+ if (NotificationClassificationFlag.isEnabled) {
+ newsHeaderController.reinflateView(parent)
+ socialHeaderController.reinflateView(parent)
+ recsHeaderController.reinflateView(parent)
+ promoHeaderController.reinflateView(parent)
+ }
}
override fun beginsSection(view: View, previous: View?): Boolean =
view === silentHeaderView ||
- view === mediaControlsView ||
- view === peopleHeaderView ||
- view === alertingHeaderView ||
- view === incomingHeaderView ||
- getBucket(view) != getBucket(previous)
+ view === mediaControlsView ||
+ view === peopleHeaderView ||
+ view === alertingHeaderView ||
+ view === incomingHeaderView ||
+ (NotificationClassificationFlag.isEnabled && (view === newsHeaderView
+ || view === socialHeaderView || view === recsHeaderView
+ || view === promoHeaderView)) ||
+ getBucket(view) != getBucket(previous)
private fun getBucket(view: View?): Int? =
when {
@@ -124,6 +151,10 @@
view === mediaControlsView -> BUCKET_MEDIA_CONTROLS
view === peopleHeaderView -> BUCKET_PEOPLE
view === alertingHeaderView -> BUCKET_ALERTING
+ view === newsHeaderView -> BUCKET_NEWS
+ view === socialHeaderView -> BUCKET_SOCIAL
+ view === recsHeaderView -> BUCKET_RECS
+ view === promoHeaderView -> BUCKET_PROMO
view is ExpandableNotificationRow -> view.entry.bucket
else -> null
}
@@ -255,6 +286,12 @@
peopleHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
silentHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
alertingHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+ if (NotificationClassificationFlag.isEnabled) {
+ newsHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+ socialHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+ recsHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+ promoHeaderView?.setForegroundColors(onSurface, onSurfaceVariant)
+ }
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 4ce9010..0623bb2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -107,7 +107,6 @@
private int mStatusBarState;
private AnimationStateHandler mAnimationStateHandler;
- private Handler mBgHandler;
private int mHeadsUpInset;
// Used for determining the region for touch interaction
@@ -152,8 +151,7 @@
UiEventLogger uiEventLogger,
JavaAdapter javaAdapter,
ShadeInteractor shadeInteractor,
- AvalancheController avalancheController,
- @Background Handler bgHandler) {
+ AvalancheController avalancheController) {
super(context, logger, handler, globalSettings, systemClock, executor,
accessibilityManagerWrapper, uiEventLogger, avalancheController);
Resources resources = mContext.getResources();
@@ -163,7 +161,6 @@
mGroupMembershipManager = groupMembershipManager;
mVisualStabilityProvider = visualStabilityProvider;
mAvalancheController = avalancheController;
- mBgHandler = bgHandler;
updateResources();
configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
@Override
@@ -405,11 +402,8 @@
// Waiting HUNs in AvalancheController are still promoted to the HUN section and thus
// seen in open shade; clear them so we don't show them again when the shade closes and
// reordering is allowed again.
- int waitingKeysSize = mAvalancheController.getWaitingKeys().size();
- mBgHandler.post(() -> {
- // Do this in the background to avoid missing frames when closing the shade
- mAvalancheController.logDroppedHuns(waitingKeysSize);
- });
+ final int numDropped = mAvalancheController.getWaitingKeys().size();
+ mAvalancheController.logDroppedHunsInBackground(numDropped);
mAvalancheController.clearNext();
// In open shade the first HUN is pinned, and visual stability logic prevents us from
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
index dbe54f3..8aabdf2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AvalancheController.kt
@@ -15,12 +15,14 @@
*/
package com.android.systemui.statusbar.policy
+import android.os.Handler
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.internal.logging.UiEvent
import com.android.internal.logging.UiEventLogger
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
import com.android.systemui.statusbar.policy.BaseHeadsUpManager.HeadsUpEntry
@@ -35,7 +37,10 @@
@SysUISingleton
class AvalancheController
@Inject
-constructor(dumpManager: DumpManager, private val uiEventLogger: UiEventLogger) : Dumpable {
+constructor(dumpManager: DumpManager,
+ private val uiEventLogger: UiEventLogger,
+ @Background private val bgHandler: Handler
+) : Dumpable {
private val tag = "AvalancheController"
private val debug = Compile.IS_DEBUG && Log.isLoggable(tag, Log.DEBUG)
@@ -315,7 +320,7 @@
// Remove runnable labels for dropped huns
val listToDrop = nextList.subList(1, nextList.size)
- logDroppedHuns(listToDrop.size)
+ logDroppedHunsInBackground(listToDrop.size)
if (debug) {
// Clear runnable labels
@@ -332,10 +337,13 @@
showNow(headsUpEntryShowing!!, headsUpEntryShowingRunnableList)
}
- fun logDroppedHuns(numDropped: Int) {
- for (n in 1..numDropped) {
- uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_DROPPED)
- }
+ fun logDroppedHunsInBackground(numDropped: Int) {
+ bgHandler.post(Runnable {
+ // Do this in the background to avoid missing frames when closing the shade
+ for (n in 1..numDropped) {
+ uiEventLogger.log(ThrottleEvent.AVALANCHE_THROTTLING_HUN_DROPPED)
+ }
+ })
}
fun clearNext() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 9a99ed7..1e3ee28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -27,6 +27,7 @@
import android.hardware.biometrics.PromptInfo
import android.hardware.biometrics.PromptVerticalListContentView
import android.hardware.face.FaceSensorPropertiesInternal
+import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.os.Handler
import android.os.IBinder
@@ -88,9 +89,8 @@
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
-
+import org.mockito.junit.MockitoJUnit
private const val OP_PACKAGE_NAME = "biometric.testapp"
@@ -99,33 +99,21 @@
@SmallTest
open class AuthContainerViewTest : SysuiTestCase() {
- @JvmField @Rule
- var mockitoRule = MockitoJUnit.rule()
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
- @Mock
- lateinit var callback: AuthDialogCallback
- @Mock
- lateinit var userManager: UserManager
- @Mock
- lateinit var lockPatternUtils: LockPatternUtils
- @Mock
- lateinit var wakefulnessLifecycle: WakefulnessLifecycle
- @Mock
- lateinit var panelInteractionDetector: AuthDialogPanelInteractionDetector
- @Mock
- lateinit var windowToken: IBinder
- @Mock
- lateinit var interactionJankMonitor: InteractionJankMonitor
- @Mock
- lateinit var vibrator: VibratorHelper
- @Mock
- lateinit var udfpsUtils: UdfpsUtils
- @Mock
- lateinit var authController: AuthController
- @Mock
- lateinit var selectedUserInteractor: SelectedUserInteractor
- @Mock
- private lateinit var packageManager: PackageManager
+ @Mock lateinit var callback: AuthDialogCallback
+ @Mock lateinit var userManager: UserManager
+ @Mock lateinit var fingerprintManager: FingerprintManager
+ @Mock lateinit var lockPatternUtils: LockPatternUtils
+ @Mock lateinit var wakefulnessLifecycle: WakefulnessLifecycle
+ @Mock lateinit var panelInteractionDetector: AuthDialogPanelInteractionDetector
+ @Mock lateinit var windowToken: IBinder
+ @Mock lateinit var interactionJankMonitor: InteractionJankMonitor
+ @Mock lateinit var vibrator: VibratorHelper
+ @Mock lateinit var udfpsUtils: UdfpsUtils
+ @Mock lateinit var authController: AuthController
+ @Mock lateinit var selectedUserInteractor: SelectedUserInteractor
+ @Mock private lateinit var packageManager: PackageManager
@Mock private lateinit var activityTaskManager: ActivityTaskManager
private lateinit var displayRepository: FakeDisplayRepository
@@ -141,11 +129,12 @@
private val fingerprintRepository = FakeFingerprintPropertyRepository()
private val displayStateRepository = FakeDisplayStateRepository()
private val credentialInteractor = FakeCredentialInteractor()
- private val bpCredentialInteractor = PromptCredentialInteractor(
- Dispatchers.Main.immediate,
- biometricPromptRepository,
- credentialInteractor,
- )
+ private val bpCredentialInteractor =
+ PromptCredentialInteractor(
+ Dispatchers.Main.immediate,
+ biometricPromptRepository,
+ credentialInteractor,
+ )
private val promptSelectorInteractor by lazy {
PromptSelectorInteractorImpl(
fingerprintRepository,
@@ -166,22 +155,26 @@
displayStateInteractor =
DisplayStateInteractorImpl(
- testScope.backgroundScope,
- mContext,
- fakeExecutor,
- displayStateRepository,
- displayRepository,
+ testScope.backgroundScope,
+ mContext,
+ fakeExecutor,
+ displayStateRepository,
+ displayRepository,
)
udfpsOverlayInteractor =
- UdfpsOverlayInteractor(
- context,
- authController,
- selectedUserInteractor,
- testScope.backgroundScope,
- )
+ UdfpsOverlayInteractor(
+ context,
+ authController,
+ selectedUserInteractor,
+ fingerprintManager,
+ testScope.backgroundScope,
+ )
biometricStatusInteractor =
- BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository,
- fingerprintRepository)
+ BiometricStatusInteractorImpl(
+ activityTaskManager,
+ biometricStatusRepository,
+ fingerprintRepository
+ )
iconProvider = IconProvider(context)
// Set up default logo icon
whenever(packageManager.getApplicationIcon(OP_PACKAGE_NAME)).thenReturn(defaultLogoIcon)
@@ -198,10 +191,8 @@
@Test
fun testNotifiesAnimatedIn() {
initializeFingerprintContainer()
- verify(callback).onDialogAnimatedIn(
- authContainer?.requestId ?: 0L,
- true /* startFingerprintNow */
- )
+ verify(callback)
+ .onDialogAnimatedIn(authContainer?.requestId ?: 0L, true /* startFingerprintNow */)
}
@Test
@@ -246,10 +237,8 @@
waitForIdleSync()
// attaching the view resets the state and allows this to happen again
- verify(callback).onDialogAnimatedIn(
- authContainer?.requestId ?: 0L,
- true /* startFingerprintNow */
- )
+ verify(callback)
+ .onDialogAnimatedIn(authContainer?.requestId ?: 0L, true /* startFingerprintNow */)
}
@Test
@@ -274,10 +263,8 @@
// the first time is triggered by initializeFingerprintContainer()
// the second time was triggered by dismissWithoutCallback()
- verify(callback, times(2)).onDialogAnimatedIn(
- authContainer?.requestId ?: 0L,
- true /* startFingerprintNow */
- )
+ verify(callback, times(2))
+ .onDialogAnimatedIn(authContainer?.requestId ?: 0L, true /* startFingerprintNow */)
}
@Test
@@ -288,18 +275,18 @@
verify(panelInteractionDetector).disable()
}
-
@Test
fun testActionAuthenticated_sendsDismissedAuthenticated() {
val container = initializeFingerprintContainer()
container.mBiometricCallback.onAuthenticated()
waitForIdleSync()
- verify(callback).onDismissed(
+ verify(callback)
+ .onDismissed(
eq(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L)
- )
+ )
assertThat(container.parent).isNull()
}
@@ -309,15 +296,17 @@
container.mBiometricCallback.onUserCanceled()
waitForIdleSync()
- verify(callback).onSystemEvent(
+ verify(callback)
+ .onSystemEvent(
eq(BiometricConstants.BIOMETRIC_SYSTEM_EVENT_EARLY_USER_CANCEL),
eq(authContainer?.requestId ?: 0L)
- )
- verify(callback).onDismissed(
+ )
+ verify(callback)
+ .onDismissed(
eq(AuthDialogCallback.DISMISSED_USER_CANCELED),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L)
- )
+ )
assertThat(container.parent).isNull()
}
@@ -327,19 +316,21 @@
container.mBiometricCallback.onButtonNegative()
waitForIdleSync()
- verify(callback).onDismissed(
+ verify(callback)
+ .onDismissed(
eq(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L)
- )
+ )
assertThat(container.parent).isNull()
}
@Test
fun testActionTryAgain_sendsTryAgain() {
- val container = initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK
- )
+ val container =
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK
+ )
container.mBiometricCallback.onButtonTryAgain()
waitForIdleSync()
@@ -352,21 +343,24 @@
container.mBiometricCallback.onError()
waitForIdleSync()
- verify(callback).onDismissed(
+ verify(callback)
+ .onDismissed(
eq(AuthDialogCallback.DISMISSED_ERROR),
eq<ByteArray?>(null), /* credentialAttestation */
eq(authContainer?.requestId ?: 0L)
- )
+ )
assertThat(authContainer!!.parent).isNull()
}
@Ignore("b/279650412")
@Test
fun testActionUseDeviceCredential_sendsOnDeviceCredentialPressed() {
- val container = initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
- BiometricManager.Authenticators.DEVICE_CREDENTIAL
- )
+ val container =
+ initializeFingerprintContainer(
+ authenticators =
+ BiometricManager.Authenticators.BIOMETRIC_WEAK or
+ BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
container.mBiometricCallback.onUseDeviceCredential()
waitForIdleSync()
@@ -376,10 +370,12 @@
@Test
fun testAnimateToCredentialUI_invokesStartTransitionToCredentialUI() {
- val container = initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
- BiometricManager.Authenticators.DEVICE_CREDENTIAL
- )
+ val container =
+ initializeFingerprintContainer(
+ authenticators =
+ BiometricManager.Authenticators.BIOMETRIC_WEAK or
+ BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
container.animateToCredentialUI(false)
waitForIdleSync()
@@ -395,10 +391,12 @@
@Test
fun testAnimateToCredentialUI_rotateCredentialUI() {
- val container = initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
- BiometricManager.Authenticators.DEVICE_CREDENTIAL
- )
+ val container =
+ initializeFingerprintContainer(
+ authenticators =
+ BiometricManager.Authenticators.BIOMETRIC_WEAK or
+ BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
container.animateToCredentialUI(false)
waitForIdleSync()
@@ -437,13 +435,12 @@
mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
var isButtonClicked = false
val contentView =
- PromptContentViewWithMoreOptionsButton.Builder()
- .setMoreOptionsButtonListener(
- fakeExecutor) { _, _ -> isButtonClicked = true }
- .build()
+ PromptContentViewWithMoreOptionsButton.Builder()
+ .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> isButtonClicked = true }
+ .build()
val container =
- initializeFingerprintContainer(contentViewWithMoreOptionsButton = contentView)
+ initializeFingerprintContainer(contentViewWithMoreOptionsButton = contentView)
waitForIdleSync()
@@ -461,9 +458,9 @@
@Test
fun testShowCredentialUI_withDescription() {
val container =
- initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
- )
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
waitForIdleSync()
assertThat(container.hasCredentialView()).isTrue()
@@ -475,10 +472,10 @@
mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP)
mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
val container =
- initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
- verticalListContentView = PromptVerticalListContentView.Builder().build()
- )
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
+ verticalListContentView = PromptVerticalListContentView.Builder().build()
+ )
// Two-step credential view should show -
// 1. biometric prompt without sensor 2. credential view ui
waitForIdleSync()
@@ -497,14 +494,14 @@
mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP)
mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT)
val contentView =
- PromptContentViewWithMoreOptionsButton.Builder()
- .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> }
- .build()
+ PromptContentViewWithMoreOptionsButton.Builder()
+ .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> }
+ .build()
val container =
- initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
- contentViewWithMoreOptionsButton = contentView
- )
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
+ contentViewWithMoreOptionsButton = contentView
+ )
waitForIdleSync()
assertThat(container.hasCredentialView()).isTrue()
@@ -514,13 +511,13 @@
@Test
fun testCredentialViewUsesEffectiveUserId() {
whenever(userManager.getCredentialOwnerProfile(anyInt())).thenReturn(200)
- whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(200))).thenReturn(
- DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
- )
+ whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(200)))
+ .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
- val container = initializeFingerprintContainer(
- authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
- )
+ val container =
+ initializeFingerprintContainer(
+ authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
+ )
waitForIdleSync()
assertThat(container.hasCredentialPatternView()).isTrue()
@@ -531,9 +528,8 @@
fun testCredentialUI_disablesClickingOnBackground() {
val container = initializeCredentialPasswordContainer()
assertThat(container.hasBiometricPrompt()).isFalse()
- assertThat(
- container.findViewById<View>(R.id.background)?.isImportantForAccessibility
- ).isFalse()
+ assertThat(container.findViewById<View>(R.id.background)?.isImportantForAccessibility)
+ .isFalse()
container.findViewById<View>(R.id.background)?.performClick()
waitForIdleSync()
@@ -552,7 +548,7 @@
fun testLayoutParams_hasShowWhenLockedFlag() {
val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
assertThat((layoutParams.flags and WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED) != 0)
- .isTrue()
+ .isTrue()
}
@Test
@@ -590,20 +586,20 @@
}
private fun initializeCredentialPasswordContainer(
- addToView: Boolean = true,
+ addToView: Boolean = true,
): TestAuthContainerView {
whenever(userManager.getCredentialOwnerProfile(anyInt())).thenReturn(20)
- whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(20))).thenReturn(
- DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
- )
+ whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(20)))
+ .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC)
// In the credential view, clicking on the background (to cancel authentication) is not
// valid. Thus, the listener should be null, and it should not be in the accessibility
// hierarchy.
- val container = initializeFingerprintContainer(
+ val container =
+ initializeFingerprintContainer(
authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
addToView = addToView,
- )
+ )
waitForIdleSync()
assertThat(container.hasCredentialPasswordView()).isTrue()
@@ -615,26 +611,28 @@
addToView: Boolean = true,
verticalListContentView: PromptVerticalListContentView? = null,
contentViewWithMoreOptionsButton: PromptContentViewWithMoreOptionsButton? = null,
- ) = initializeContainer(
- TestAuthContainerView(
- authenticators = authenticators,
- fingerprintProps = fingerprintSensorPropertiesInternal(),
+ ) =
+ initializeContainer(
+ TestAuthContainerView(
+ authenticators = authenticators,
+ fingerprintProps = fingerprintSensorPropertiesInternal(),
verticalListContentView = verticalListContentView,
- ),
- addToView
- )
+ ),
+ addToView
+ )
private fun initializeCoexContainer(
authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
addToView: Boolean = true
- ) = initializeContainer(
- TestAuthContainerView(
- authenticators = authenticators,
- fingerprintProps = fingerprintSensorPropertiesInternal(),
- faceProps = faceSensorPropertiesInternal()
- ),
- addToView
- )
+ ) =
+ initializeContainer(
+ TestAuthContainerView(
+ authenticators = authenticators,
+ fingerprintProps = fingerprintSensorPropertiesInternal(),
+ faceProps = faceSensorPropertiesInternal()
+ ),
+ addToView
+ )
private fun initializeContainer(
view: TestAuthContainerView,
@@ -655,47 +653,50 @@
faceProps: List<FaceSensorPropertiesInternal> = listOf(),
verticalListContentView: PromptVerticalListContentView? = null,
contentViewWithMoreOptionsButton: PromptContentViewWithMoreOptionsButton? = null,
- ) : AuthContainerView(
- Config().apply {
- mContext = this@AuthContainerViewTest.context
- mCallback = callback
- mSensorIds = (fingerprintProps.map { it.sensorId } +
- faceProps.map { it.sensorId }).toIntArray()
- mSkipAnimation = true
- mPromptInfo = PromptInfo().apply {
- this.authenticators = authenticators
- if (verticalListContentView != null) {
- this.contentView = verticalListContentView
- } else if (contentViewWithMoreOptionsButton != null) {
- this.contentView = contentViewWithMoreOptionsButton
- }
- }
- mOpPackageName = OP_PACKAGE_NAME
- },
- testScope.backgroundScope,
- fingerprintProps,
- faceProps,
- wakefulnessLifecycle,
- panelInteractionDetector,
- userManager,
- lockPatternUtils,
- interactionJankMonitor,
- { promptSelectorInteractor },
- PromptViewModel(
- displayStateInteractor,
- promptSelectorInteractor,
- context,
- udfpsOverlayInteractor,
- biometricStatusInteractor,
- udfpsUtils,
- iconProvider,
- activityTaskManager
- ),
- { credentialViewModel },
- Handler(TestableLooper.get(this).looper),
- fakeExecutor,
- vibrator
- ) {
+ ) :
+ AuthContainerView(
+ Config().apply {
+ mContext = this@AuthContainerViewTest.context
+ mCallback = callback
+ mSensorIds =
+ (fingerprintProps.map { it.sensorId } + faceProps.map { it.sensorId })
+ .toIntArray()
+ mSkipAnimation = true
+ mPromptInfo =
+ PromptInfo().apply {
+ this.authenticators = authenticators
+ if (verticalListContentView != null) {
+ this.contentView = verticalListContentView
+ } else if (contentViewWithMoreOptionsButton != null) {
+ this.contentView = contentViewWithMoreOptionsButton
+ }
+ }
+ mOpPackageName = OP_PACKAGE_NAME
+ },
+ testScope.backgroundScope,
+ fingerprintProps,
+ faceProps,
+ wakefulnessLifecycle,
+ panelInteractionDetector,
+ userManager,
+ lockPatternUtils,
+ interactionJankMonitor,
+ { promptSelectorInteractor },
+ PromptViewModel(
+ displayStateInteractor,
+ promptSelectorInteractor,
+ context,
+ udfpsOverlayInteractor,
+ biometricStatusInteractor,
+ udfpsUtils,
+ iconProvider,
+ activityTaskManager
+ ),
+ { credentialViewModel },
+ Handler(TestableLooper.get(this).looper),
+ fakeExecutor,
+ vibrator
+ ) {
override fun postOnAnimation(runnable: Runnable) {
runnable.run()
}
@@ -717,8 +718,10 @@
val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
val lpFlags = layoutParams.flags
- assertThat((lpFlags and WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS)
- != 0).isTrue()
+ assertThat(
+ (lpFlags and WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) != 0
+ )
+ .isTrue()
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
index 3d63c5b..13f2c72 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics.domain.interactor
import android.graphics.Rect
+import android.hardware.fingerprint.FingerprintManager
import android.view.MotionEvent
import android.view.Surface
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -51,6 +52,7 @@
private lateinit var testScope: TestScope
+ @Mock private lateinit var fingerprintManager: FingerprintManager
@Mock private lateinit var authController: AuthController
@Captor private lateinit var authControllerCallback: ArgumentCaptor<AuthController.Callback>
@@ -111,6 +113,7 @@
context,
authController,
selectedUserInteractor,
+ fingerprintManager,
testScope.backgroundScope
)
testScope.runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 5c45b2e..3669e3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -64,6 +64,10 @@
@Mock private SectionHeaderController mPeopleHeaderController;
@Mock private SectionHeaderController mAlertingHeaderController;
@Mock private SectionHeaderController mSilentHeaderController;
+ @Mock private SectionHeaderController mNewsHeaderController;
+ @Mock private SectionHeaderController mSocialHeaderController;
+ @Mock private SectionHeaderController mRecsHeaderController;
+ @Mock private SectionHeaderController mPromoHeaderController;
private NotificationSectionsManager mSectionsManager;
@@ -94,7 +98,11 @@
mIncomingHeaderController,
mPeopleHeaderController,
mAlertingHeaderController,
- mSilentHeaderController
+ mSilentHeaderController,
+ mNewsHeaderController,
+ mSocialHeaderController,
+ mRecsHeaderController,
+ mPromoHeaderController
);
// Required in order for the header inflation to work properly
when(mNssl.generateLayoutParams(any(AttributeSet.class)))
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 9dae44d..7c53639 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/TestMocksModule.kt
@@ -18,6 +18,7 @@
import android.app.ActivityManager
import android.app.admin.DevicePolicyManager
import android.app.trust.TrustManager
+import android.hardware.fingerprint.FingerprintManager
import android.os.UserManager
import android.service.notification.NotificationListenerService
import android.util.DisplayMetrics
@@ -94,6 +95,7 @@
@get:Provides val deviceProvisionedController: DeviceProvisionedController = mock(),
@get:Provides val dozeParameters: DozeParameters = mock(),
@get:Provides val dumpManager: DumpManager = mock(),
+ @get:Provides val fingerprintManager: FingerprintManager = mock(),
@get:Provides val headsUpManager: HeadsUpManager = mock(),
@get:Provides val guestResumeSessionReceiver: GuestResumeSessionReceiver = mock(),
@get:Provides val keyguardBypassController: KeyguardBypassController = mock(),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt
index cbfc768..ae592b9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/UdfpsOverlayInteractorKosmos.kt
@@ -17,17 +17,20 @@
package com.android.systemui.biometrics.domain.interactor
import android.content.applicationContext
+import android.hardware.fingerprint.FingerprintManager
import com.android.systemui.biometrics.authController
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.user.domain.interactor.selectedUserInteractor
+import com.android.systemui.util.mockito.mock
val Kosmos.udfpsOverlayInteractor by Fixture {
UdfpsOverlayInteractor(
context = applicationContext,
authController = authController,
selectedUserInteractor = selectedUserInteractor,
+ fingerprintManager = mock<FingerprintManager>(),
scope = applicationCoroutineScope,
)
}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java
index 63bcda188..4992c4b 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodBaseContext.java
@@ -447,14 +447,6 @@
}
@Override
- public void sendOrderedBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
- String[] receiverPermissions, int appOp, Bundle options,
- BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
- String initialData, Bundle initialExtras) {
- throw notSupported();
- }
-
- @Override
public void sendStickyBroadcast(Intent intent) {
throw notSupported();
}
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index c4d38e4..a2bbff0 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -48,3 +48,6 @@
# SystemConfig
per-file SystemConfig.java = file:/PACKAGE_MANAGER_OWNERS
+
+# CertBlocklister
+per-file Cert*.java = tweek@google.com, brambonne@google.com, prb@google.com, miguelaranda@google.com
diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java
index 598f086..4faadcb 100644
--- a/services/core/java/com/android/server/am/LmkdConnection.java
+++ b/services/core/java/com/android/server/am/LmkdConnection.java
@@ -91,10 +91,18 @@
@GuardedBy("mLmkdSocketLock")
private LocalSocket mLmkdSocket = null;
- // socket I/O streams
- @GuardedBy("mLmkdSocketLock")
+ // mutex to synchronize socket output stream with socket creation/destruction
+ private final Object mLmkdOutputStreamLock = new Object();
+
+ // socket output stream
+ @GuardedBy("mLmkdOutputStreamLock")
private OutputStream mLmkdOutputStream = null;
- @GuardedBy("mLmkdSocketLock")
+
+ // mutex to synchronize socket input stream with socket creation/destruction
+ private final Object mLmkdInputStreamLock = new Object();
+
+ // socket input stream
+ @GuardedBy("mLmkdInputStreamLock")
private InputStream mLmkdInputStream = null;
// buffer to store incoming data
@@ -148,9 +156,13 @@
return false;
}
// connection established
- mLmkdSocket = socket;
- mLmkdOutputStream = ostream;
- mLmkdInputStream = istream;
+ synchronized(mLmkdOutputStreamLock) {
+ synchronized(mLmkdInputStreamLock) {
+ mLmkdSocket = socket;
+ mLmkdOutputStream = ostream;
+ mLmkdInputStream = istream;
+ }
+ }
mMsgQueue.addOnFileDescriptorEventListener(mLmkdSocket.getFileDescriptor(),
EVENT_INPUT | EVENT_ERROR,
new MessageQueue.OnFileDescriptorEventListener() {
@@ -177,7 +189,13 @@
mMsgQueue.removeOnFileDescriptorEventListener(
mLmkdSocket.getFileDescriptor());
IoUtils.closeQuietly(mLmkdSocket);
- mLmkdSocket = null;
+ synchronized(mLmkdOutputStreamLock) {
+ synchronized(mLmkdInputStreamLock) {
+ mLmkdOutputStream = null;
+ mLmkdInputStream = null;
+ mLmkdSocket = null;
+ }
+ }
}
// wake up reply waiters if any
synchronized (mReplyBufLock) {
@@ -262,24 +280,33 @@
}
private boolean write(ByteBuffer buf) {
- synchronized (mLmkdSocketLock) {
- try {
- mLmkdOutputStream.write(buf.array(), 0, buf.position());
- } catch (IOException ex) {
- return false;
+ boolean result = false;
+
+ synchronized(mLmkdOutputStreamLock) {
+ if (mLmkdOutputStream != null) {
+ try {
+ mLmkdOutputStream.write(buf.array(), 0, buf.position());
+ result = true;
+ } catch (IOException ex) {
+ }
}
- return true;
}
+
+ return result;
}
private int read(ByteBuffer buf) {
- synchronized (mLmkdSocketLock) {
- try {
- return mLmkdInputStream.read(buf.array(), 0, buf.array().length);
- } catch (IOException ex) {
+ int result = -1;
+
+ synchronized(mLmkdInputStreamLock) {
+ if (mLmkdInputStream != null) {
+ try {
+ result = mLmkdInputStream.read(buf.array(), 0, buf.array().length);
+ } catch (IOException ex) {
+ }
}
- return -1;
}
+ return result;
}
/**
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index d061e2d..fbd32a6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -31,7 +31,6 @@
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
-import com.android.server.biometrics.sensors.fingerprint.aidl.AidlSession;
import java.util.function.Supplier;
@@ -203,16 +202,6 @@
}
}
- // TODO(b/317414324): Deprecate setIgnoreDisplayTouches
- protected final void resetIgnoreDisplayTouches() {
- final AidlSession session = (AidlSession) getFreshDaemon();
- try {
- session.getSession().setIgnoreDisplayTouches(false);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when resetting setIgnoreDisplayTouches");
- }
- }
-
@Override
public boolean isInterruptable() {
return true;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 4c86f57..60cfd5a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -962,6 +962,19 @@
provider.onUdfpsUiEvent(event, requestId, sensorId);
}
+ @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
+ @Override
+ public void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches) {
+ super.setIgnoreDisplayTouches_enforcePermission();
+
+ final ServiceProvider provider = mRegistry.getProviderForSensor(sensorId);
+ if (provider == null) {
+ Slog.w(TAG,
+ "No matching provider for setIgnoreDisplayTouches, sensorId: " + sensorId);
+ return;
+ }
+ provider.setIgnoreDisplayTouches(requestId, sensorId, ignoreTouches);
+ }
@android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL)
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index a6cf2f4..e4a99e6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -134,6 +134,8 @@
void setUdfpsOverlayController(@NonNull IUdfpsOverlayController controller);
+ void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches);
+
void onPowerPressed();
@NonNull
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java
index dce0175..15d7a47 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Udfps.java
@@ -31,4 +31,5 @@
void onPointerUp(PointerContext pc);
void onUdfpsUiEvent(@FingerprintManager.UdfpsUiEvent int event);
boolean isPointerDown();
+ void setIgnoreDisplayTouches(boolean ignoreTouches);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 72d92b9..d04afdb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -33,7 +33,6 @@
import android.hardware.biometrics.BiometricManager.Authenticators;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.common.ICancellationSignal;
-import android.hardware.biometrics.common.OperationState;
import android.hardware.biometrics.events.AuthenticationAcquiredInfo;
import android.hardware.biometrics.events.AuthenticationErrorInfo;
import android.hardware.biometrics.events.AuthenticationFailedInfo;
@@ -182,7 +181,6 @@
handleLockout(authenticated);
if (authenticated) {
mState = STATE_STOPPED;
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
if (reportBiometricAuthAttempts()) {
mAuthenticationStateListeners.onAuthenticationSucceeded(
@@ -223,7 +221,6 @@
// Send the error, but do not invoke the FinishCallback yet. Since lockout is not
// controlled by the HAL, the framework must stop the sensor before finishing the
// client.
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationError(
new AuthenticationErrorInfo.Builder(BiometricSourceType.FINGERPRINT,
@@ -275,7 +272,6 @@
BiometricNotificationUtils.showBadCalibrationNotification(getContext());
}
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo
.Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build()
@@ -284,7 +280,6 @@
@Override
protected void startHalOperation() {
- resetIgnoreDisplayTouches();
mSensorOverlays.show(getSensorId(), getRequestReason(), this);
mAuthenticationStateListeners.onAuthenticationStarted(new AuthenticationStartedInfo
.Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build()
@@ -331,12 +326,6 @@
if (session.hasContextMethods()) {
try {
session.getSession().onContextChanged(ctx);
- // TODO(b/317414324): Deprecate setIgnoreDisplayTouches
- if (ctx.operationState != null && ctx.operationState.getTag()
- == OperationState.fingerprintOperationState) {
- session.getSession().setIgnoreDisplayTouches(ctx.operationState
- .getFingerprintOperationState().isHardwareIgnoringTouches);
- }
} catch (RemoteException e) {
Slog.e(TAG, "Unable to notify context changed", e);
}
@@ -353,7 +342,6 @@
@Override
protected void stopHalOperation() {
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo
.Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build()
@@ -415,6 +403,15 @@
}
@Override
+ public void setIgnoreDisplayTouches(boolean ignoreTouches) {
+ try {
+ getFreshDaemon().getSession().setIgnoreDisplayTouches(ignoreTouches);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ @Override
public boolean isPointerDown() {
return mIsPointerDown;
}
@@ -457,7 +454,6 @@
Slog.e(TAG, "Remote exception", e);
}
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo
.Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build()
@@ -492,7 +488,6 @@
Slog.e(TAG, "Remote exception", e);
}
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo
.Builder(BiometricSourceType.FINGERPRINT, getRequestReason()).build()
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index 36af5db..fb48053 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -87,7 +87,6 @@
@Override
protected void stopHalOperation() {
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(
new AuthenticationStoppedInfo.Builder(BiometricSourceType.FINGERPRINT,
@@ -107,7 +106,6 @@
@Override
protected void startHalOperation() {
- resetIgnoreDisplayTouches();
mSensorOverlays.show(getSensorId(), BiometricRequestConstants.REASON_AUTH_KEYGUARD,
this);
mAuthenticationStateListeners.onAuthenticationStarted(
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 3a72d7e..993a68f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -150,7 +150,6 @@
controller -> controller.onEnrollmentProgress(getSensorId(), remaining));
if (remaining == 0) {
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(
new AuthenticationStoppedInfo.Builder(
@@ -211,7 +210,6 @@
);
super.onError(errorCode, vendorCode);
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(
new AuthenticationStoppedInfo.Builder(BiometricSourceType.FINGERPRINT,
@@ -227,7 +225,6 @@
@Override
protected void startHalOperation() {
- resetIgnoreDisplayTouches();
mSensorOverlays.show(getSensorId(),
getRequestReasonFromFingerprintEnrollReason(mEnrollReason), this);
mAuthenticationStateListeners.onAuthenticationStarted(new AuthenticationStartedInfo
@@ -277,7 +274,6 @@
@Override
protected void stopHalOperation() {
- resetIgnoreDisplayTouches();
mSensorOverlays.hide(getSensorId());
mAuthenticationStateListeners.onAuthenticationStopped(new AuthenticationStoppedInfo
.Builder(BiometricSourceType.FINGERPRINT,
@@ -359,5 +355,14 @@
}
@Override
+ public void setIgnoreDisplayTouches(boolean ignoreTouches) {
+ try {
+ getFreshDaemon().getSession().setIgnoreDisplayTouches(ignoreTouches);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to send setIgnoreDisplayTouches", e);
+ }
+ }
+
+ @Override
public void onPowerPressed() {}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 1bddb83b..12baf00 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -790,6 +790,19 @@
}
@Override
+ public void setIgnoreDisplayTouches(long requestId, int sensorId, boolean ignoreTouches) {
+ mFingerprintSensors.get(sensorId).getScheduler().getCurrentClientIfMatches(
+ requestId, (client) -> {
+ if (!(client instanceof Udfps)) {
+ Slog.e(getTag(),
+ "setIgnoreDisplayTouches received during client: " + client);
+ return;
+ }
+ ((Udfps) client).setIgnoreDisplayTouches(ignoreTouches);
+ });
+ }
+
+ @Override
public void onPowerPressed() {
for (int i = 0; i < mFingerprintSensors.size(); i++) {
final Sensor sensor = mFingerprintSensors.valueAt(i);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 1dfdc55..fbb6ccf 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -195,6 +195,7 @@
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -298,22 +299,21 @@
private final String[] mNonPreemptibleInputMethods;
/**
- * See {@link #shouldEnableExperimentalConcurrentMultiUserMode(Context)} about when set to be
- * {@code true}.
+ * See {@link #shouldEnableConcurrentMultiUserMode(Context)} about when set to be {@code true}.
*/
@SharedByAllUsersField
- private final boolean mExperimentalConcurrentMultiUserModeEnabled;
+ private final boolean mConcurrentMultiUserModeEnabled;
/**
- * Returns {@code true} if experimental concurrent multi-user mode is enabled.
+ * Returns {@code true} if the concurrent multi-user mode is enabled.
*
* <p>Currently not compatible with profiles (e.g. work profile).</p>
*
* @param context {@link Context} to be used to query
* {@link PackageManager#FEATURE_AUTOMOTIVE}
- * @return {@code true} if experimental concurrent multi-user mode is enabled.
+ * @return {@code true} if the concurrent multi-user mode is enabled.
*/
- static boolean shouldEnableExperimentalConcurrentMultiUserMode(@NonNull Context context) {
+ static boolean shouldEnableConcurrentMultiUserMode(@NonNull Context context) {
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
&& UserManager.isVisibleBackgroundUsersEnabled()
&& context.getResources().getBoolean(android.R.bool.config_perDisplayFocusEnabled)
@@ -330,7 +330,7 @@
@UserIdInt
@BinderThread
private int resolveImeUserIdLocked(@UserIdInt int callingProcessUserId) {
- return mExperimentalConcurrentMultiUserModeEnabled ? callingProcessUserId : mCurrentUserId;
+ return mConcurrentMultiUserModeEnabled ? callingProcessUserId : mCurrentUserId;
}
final Context mContext;
@@ -571,10 +571,6 @@
private final ImeTrackerService mImeTrackerService;
class SettingsObserver extends ContentObserver {
- int mUserId;
- boolean mRegistered = false;
- @NonNull
- String mLastEnabled = "";
/**
* <em>This constructor must be called within the lock.</em>
@@ -583,37 +579,29 @@
super(handler);
}
- @GuardedBy("ImfLock.class")
- public void registerContentObserverLocked(@UserIdInt int userId) {
- if (mRegistered && mUserId == userId) {
- return;
- }
+ void registerContentObserverForAllUsers() {
ContentResolver resolver = mContext.getContentResolver();
- if (mRegistered) {
- mContext.getContentResolver().unregisterContentObserver(this);
- mRegistered = false;
- }
- if (mUserId != userId) {
- mLastEnabled = "";
- mUserId = userId;
- }
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.DEFAULT_INPUT_METHOD), false, this, userId);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ENABLED_INPUT_METHODS), false, this, userId);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
- STYLUS_HANDWRITING_ENABLED), false, this);
- mRegistered = true;
+ resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
+ Settings.Secure.DEFAULT_INPUT_METHOD), false, this, UserHandle.ALL);
+ resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
+ Settings.Secure.ENABLED_INPUT_METHODS), false, this, UserHandle.ALL);
+ resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
+ Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, UserHandle.ALL);
+ resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
+ Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, UserHandle.ALL);
+ resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, UserHandle.ALL);
+ resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
+ STYLUS_HANDWRITING_ENABLED), false, this, UserHandle.ALL);
}
@Override
- public void onChange(boolean selfChange, Uri uri) {
+ public void onChange(boolean selfChange, @NonNull Collection<Uri> uris, int flags,
+ @UserIdInt int userId) {
+ uris.forEach(uri -> onChangeInternal(uri, userId));
+ }
+
+ private void onChangeInternal(@NonNull Uri uri, @UserIdInt int userId) {
final Uri showImeUri = Settings.Secure.getUriFor(
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
@@ -621,23 +609,27 @@
final Uri stylusHandwritingEnabledUri = Settings.Secure.getUriFor(
STYLUS_HANDWRITING_ENABLED);
synchronized (ImfLock.class) {
+ if (!mConcurrentMultiUserModeEnabled && mCurrentUserId != userId) {
+ return;
+ }
+
if (showImeUri.equals(uri)) {
mMenuController.updateKeyboardFromSettingsLocked();
} else if (accessibilityRequestingNoImeUri.equals(uri)) {
final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, mUserId);
+ Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, userId);
mVisibilityStateComputer.getImePolicy().setA11yRequestNoSoftKeyboard(
accessibilitySoftKeyboardSetting);
- final var userData = getUserData(mUserId);
+ final var userData = getUserData(userId);
if (mVisibilityStateComputer.getImePolicy().isA11yRequestNoSoftKeyboard()) {
hideCurrentInputLocked(userData.mImeBindingState.mFocusedWindow,
0 /* flags */, SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE,
- mUserId);
- } else if (isShowRequestedForCurrentWindow(mUserId)) {
+ userId);
+ } else if (isShowRequestedForCurrentWindow(userId)) {
showCurrentInputLocked(userData.mImeBindingState.mFocusedWindow,
InputMethodManager.SHOW_IMPLICIT,
- SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE, mUserId);
+ SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE, userId);
}
} else if (stylusHandwritingEnabledUri.equals(uri)) {
InputMethodManager.invalidateLocalStylusHandwritingAvailabilityCaches();
@@ -645,22 +637,17 @@
.invalidateLocalConnectionlessStylusHandwritingAvailabilityCaches();
} else {
boolean enabledChanged = false;
- String newEnabled = InputMethodSettingsRepository.get(mUserId)
+ String newEnabled = InputMethodSettingsRepository.get(userId)
.getEnabledInputMethodsStr();
- if (!mLastEnabled.equals(newEnabled)) {
- mLastEnabled = newEnabled;
+ final var userData = getUserData(userId);
+ if (!userData.mLastEnabledInputMethodsStr.equals(newEnabled)) {
+ userData.mLastEnabledInputMethodsStr = newEnabled;
enabledChanged = true;
}
- updateInputMethodsFromSettingsLocked(enabledChanged, mUserId);
+ updateInputMethodsFromSettingsLocked(enabledChanged, userId);
}
}
}
-
- @Override
- public String toString() {
- return "SettingsObserver{mUserId=" + mUserId + " mRegistered=" + mRegistered
- + " mLastEnabled=" + mLastEnabled + "}";
- }
}
/**
@@ -973,7 +960,7 @@
public Lifecycle(Context context) {
this(context, new InputMethodManagerService(context,
- shouldEnableExperimentalConcurrentMultiUserMode(context)));
+ shouldEnableConcurrentMultiUserMode(context)));
}
public Lifecycle(
@@ -1003,7 +990,7 @@
public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
// Called on ActivityManager thread.
synchronized (ImfLock.class) {
- if (mService.mExperimentalConcurrentMultiUserModeEnabled) {
+ if (mService.mConcurrentMultiUserModeEnabled) {
// In concurrent multi-user mode, we in general do not rely on the concept of
// current user.
return;
@@ -1037,9 +1024,9 @@
SecureSettingsWrapper.onUserStarting(userId);
synchronized (ImfLock.class) {
mService.getUserData(userId);
- if (mService.mExperimentalConcurrentMultiUserModeEnabled) {
+ if (mService.mConcurrentMultiUserModeEnabled) {
if (mService.mCurrentUserId != userId && mService.mSystemReady) {
- mService.experimentalInitializeVisibleBackgroundUserLocked(userId);
+ mService.initializeVisibleBackgroundUserLocked(userId);
}
}
}
@@ -1062,8 +1049,8 @@
// We need to rebuild IMEs.
postInputMethodSettingUpdatedLocked(false /* resetDefaultEnabledIme */, userId);
updateInputMethodsFromSettingsLocked(true /* enabledChanged */, userId);
- } else if (mExperimentalConcurrentMultiUserModeEnabled) {
- experimentalInitializeVisibleBackgroundUserLocked(userId);
+ } else if (mConcurrentMultiUserModeEnabled) {
+ initializeVisibleBackgroundUserLocked(userId);
}
}
}
@@ -1090,20 +1077,19 @@
}
public InputMethodManagerService(Context context,
- boolean experimentalConcurrentMultiUserModeEnabled) {
- this(context, experimentalConcurrentMultiUserModeEnabled, null, null, null);
+ boolean concurrentMultiUserModeEnabled) {
+ this(context, concurrentMultiUserModeEnabled, null, null, null);
}
@VisibleForTesting
InputMethodManagerService(
Context context,
- boolean experimentalConcurrentMultiUserModeEnabled,
+ boolean concurrentMultiUserModeEnabled,
@Nullable ServiceThread serviceThreadForTesting,
@Nullable ServiceThread ioThreadForTesting,
@Nullable IntFunction<InputMethodBindingController> bindingControllerForTesting) {
synchronized (ImfLock.class) {
- mExperimentalConcurrentMultiUserModeEnabled =
- experimentalConcurrentMultiUserModeEnabled;
+ mConcurrentMultiUserModeEnabled = concurrentMultiUserModeEnabled;
mContext = context;
mRes = context.getResources();
SecureSettingsWrapper.onStart(mContext);
@@ -1307,11 +1293,12 @@
maybeInitImeNavbarConfigLocked(newUserId);
- // ContentObserver should be registered again when the user is changed
- mSettingsObserver.registerContentObserverLocked(newUserId);
+ final var newUserData = getUserData(newUserId);
+
+ // TODO(b/342027196): Double check if we need to always reset upon user switching.
+ newUserData.mLastEnabledInputMethodsStr = "";
mCurrentUserId = newUserId;
- final var newUserData = getUserData(newUserId);
final String defaultImiId = SecureSettingsWrapper.getString(
Settings.Secure.DEFAULT_INPUT_METHOD, null, newUserId);
@@ -1402,7 +1389,7 @@
}, "Lazily initialize IMMS#mImeDrawsImeNavBarRes");
mMyPackageMonitor.register(mContext, UserHandle.ALL, mIoHandler);
- mSettingsObserver.registerContentObserverLocked(currentUserId);
+ mSettingsObserver.registerContentObserverForAllUsers();
final IntentFilter broadcastFilterForAllUsers = new IntentFilter();
broadcastFilterForAllUsers.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -1428,10 +1415,10 @@
AdditionalSubtypeMapRepository::startWriterThread,
"Start AdditionalSubtypeMapRepository's writer thread");
- if (mExperimentalConcurrentMultiUserModeEnabled) {
+ if (mConcurrentMultiUserModeEnabled) {
for (int userId : mUserManagerInternal.getUserIds()) {
if (userId != mCurrentUserId) {
- experimentalInitializeVisibleBackgroundUserLocked(userId);
+ initializeVisibleBackgroundUserLocked(userId);
}
}
}
@@ -2538,7 +2525,7 @@
@SuppressWarnings("GuardedBy") Consumer<ClientState> clearClientSession = c -> {
// TODO(b/305849394): Figure out what we should do for single user IME mode.
final boolean shouldClearClientSession =
- !mExperimentalConcurrentMultiUserModeEnabled
+ !mConcurrentMultiUserModeEnabled
|| UserHandle.getUserId(c.mUid) == userId;
if (shouldClearClientSession) {
clearClientSessionLocked(c);
@@ -2840,27 +2827,25 @@
}
/**
- * This is an experimental implementation used when and only when
- * {@link #mExperimentalConcurrentMultiUserModeEnabled}.
+ * This initialization logic is used when and only when {@link #mConcurrentMultiUserModeEnabled}
+ * is set to {@code true}.
*
- * <p>Never assume what this method is doing is officially supported. For the canonical and
- * desired behaviors always refer to single-user code paths such as
+ * <p>There remain several yet-to-be-implemented features. For the canonical and desired
+ * behaviors always refer to single-user code paths such as
* {@link #updateInputMethodsFromSettingsLocked(boolean, int)}.</p>
*
* <p>Here are examples of missing features.</p>
* <ul>
- * <li>Subtypes are not supported at all!</li>
* <li>Profiles are not supported.</li>
* <li>
* {@link PackageManager#COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED} is not updated.
* </li>
* <li>{@link InputMethodBindingController#getDeviceIdToShowIme()} is ignored.</li>
- * <li>{@link #mPreventImeStartupUnlessTextEditor} is ignored.</li>
* <li>and so on.</li>
* </ul>
*/
@GuardedBy("ImfLock.class")
- void experimentalInitializeVisibleBackgroundUserLocked(@UserIdInt int userId) {
+ void initializeVisibleBackgroundUserLocked(@UserIdInt int userId) {
final var settings = InputMethodSettingsRepository.get(userId);
// Until we figure out what makes most sense, we enable all the pre-installed IMEs in
@@ -2868,7 +2853,7 @@
String enabledImeIdsStr = settings.getEnabledInputMethodsStr();
for (var imi : settings.getMethodList()) {
if (!imi.isSystem()) {
- return;
+ continue;
}
enabledImeIdsStr = InputMethodUtils.concatEnabledImeIds(enabledImeIdsStr, imi.getId());
}
@@ -2881,19 +2866,18 @@
if (TextUtils.isEmpty(id)) {
final InputMethodInfo imi = InputMethodInfoUtils.getMostApplicableDefaultIME(
settings.getEnabledInputMethodList());
- if (imi == null) {
- return;
+ if (imi != null) {
+ id = imi.getId();
+ settings.putSelectedInputMethod(id);
}
- id = imi.getId();
- settings.putSelectedInputMethod(id);
}
+ final var bindingController = getInputMethodBindingController(userId);
+ bindingController.setSelectedMethodId(id);
+ // Also re-initialize controllers.
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")
@@ -3701,8 +3685,7 @@
final long ident = Binder.clearCallingIdentity();
try {
// Verify if IMMS is in the process of switching user.
- if (!mExperimentalConcurrentMultiUserModeEnabled
- && mUserSwitchHandlerTask != null) {
+ if (!mConcurrentMultiUserModeEnabled && mUserSwitchHandlerTask != null) {
// There is already an on-going pending user switch task.
final int nextUserId = mUserSwitchHandlerTask.mToUserId;
if (userId == nextUserId) {
@@ -3757,7 +3740,7 @@
}
// Verify if caller is a background user.
- if (!mExperimentalConcurrentMultiUserModeEnabled && userId != mCurrentUserId) {
+ if (!mConcurrentMultiUserModeEnabled && userId != mCurrentUserId) {
if (ArrayUtils.contains(
mUserManagerInternal.getProfileIds(mCurrentUserId, false),
userId)) {
@@ -4269,9 +4252,8 @@
}
if (currentUser) {
// To avoid unnecessary "updateInputMethodsFromSettingsLocked" from happening.
- if (mSettingsObserver != null) {
- mSettingsObserver.mLastEnabled = settings.getEnabledInputMethodsStr();
- }
+ final var userData = getUserData(userId);
+ userData.mLastEnabledInputMethodsStr = settings.getEnabledInputMethodsStr();
updateInputMethodsFromSettingsLocked(false /* enabledChanged */, userId);
}
}
@@ -5539,7 +5521,7 @@
@GuardedBy("ImfLock.class")
private boolean switchToInputMethodLocked(String imeId, @UserIdInt int userId) {
final InputMethodSettings settings = InputMethodSettingsRepository.get(userId);
- if (mExperimentalConcurrentMultiUserModeEnabled || userId == mCurrentUserId) {
+ if (mConcurrentMultiUserModeEnabled || userId == mCurrentUserId) {
if (!settings.getMethodMap().containsKey(imeId)
|| !settings.getEnabledInputMethodList()
.contains(settings.getMethodMap().get(imeId))) {
@@ -6110,6 +6092,8 @@
p.println(" inFullscreenMode=" + u.mInFullscreenMode);
p.println(" switchingController:");
u.mSwitchingController.dump(p, " ");
+ p.println(" mLastEnabledInputMethodsStr="
+ + u.mLastEnabledInputMethodsStr);
};
mUserDataRepository.forAllUserData(userDataDump);
@@ -6123,11 +6107,9 @@
mVisibilityStateComputer.dump(pw, " ");
p.println(" mInFullscreenMode=" + userData.mInFullscreenMode);
p.println(" mSystemReady=" + mSystemReady + " mInteractive=" + mIsInteractive);
- p.println(" mExperimentalConcurrentMultiUserModeEnabled="
- + mExperimentalConcurrentMultiUserModeEnabled);
+ p.println(" mConcurrentMultiUserModeEnabled=" + mConcurrentMultiUserModeEnabled);
p.println(" ENABLE_HIDE_IME_CAPTION_BAR="
+ InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR);
- p.println(" mSettingsObserver=" + mSettingsObserver);
p.println(" mStylusIds=" + (mStylusIds != null
? Arrays.toString(mStylusIds.toArray()) : ""));
diff --git a/services/core/java/com/android/server/inputmethod/UserDataRepository.java b/services/core/java/com/android/server/inputmethod/UserDataRepository.java
index 48284fb..59411ad 100644
--- a/services/core/java/com/android/server/inputmethod/UserDataRepository.java
+++ b/services/core/java/com/android/server/inputmethod/UserDataRepository.java
@@ -174,6 +174,13 @@
mEnabledAccessibilitySessions = new SparseArray<>();
/**
+ * A per-user cache of {@link InputMethodSettings#getEnabledInputMethodsStr()}.
+ */
+ @GuardedBy("ImfLock.class")
+ @NonNull
+ String mLastEnabledInputMethodsStr = "";
+
+ /**
* Intended to be instantiated only from this file.
*/
private UserData(@UserIdInt int userId,
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 173fc5c..009e9b8 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -4568,7 +4568,7 @@
PackageManagerException.INTERNAL_ERROR_SYSTEM_OVERLAY_STATIC);
}
} else {
- if ((scanFlags & SCAN_AS_VENDOR) != 0) {
+ if ((scanFlags & (SCAN_AS_VENDOR | SCAN_AS_ODM)) != 0) {
if (pkg.getTargetSdkVersion() < ScanPackageUtils.getVendorPartitionVersion()) {
Slog.w(TAG, "System overlay " + pkg.getPackageName()
+ " targets an SDK below the required SDK level of vendor"
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c0b8034..2e63cdb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -186,6 +186,7 @@
import com.android.internal.pm.pkg.component.ParsedMainComponent;
import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.telephony.CarrierAppUtils;
+import com.android.internal.telephony.TelephonyPermissions;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.ConcurrentUtils;
@@ -4492,8 +4493,7 @@
void setSystemAppHiddenUntilInstalled(@NonNull Computer snapshot, String packageName,
boolean hidden) {
final int callingUid = Binder.getCallingUid();
- final boolean calledFromSystemOrPhone = callingUid == Process.PHONE_UID
- || callingUid == Process.SYSTEM_UID;
+ final boolean calledFromSystemOrPhone = TelephonyPermissions.isSystemOrPhone(callingUid);
if (!calledFromSystemOrPhone) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
"setSystemAppHiddenUntilInstalled");
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index ff8abf8..924b36c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -92,6 +92,7 @@
import com.android.internal.content.InstallLocationUtils;
import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.telephony.TelephonyPermissions;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.HexDump;
@@ -356,7 +357,7 @@
* If not, throws a {@link SecurityException}.
*/
public static void enforceSystemOrPhoneCaller(String methodName, int callingUid) {
- if (callingUid != Process.PHONE_UID && callingUid != Process.SYSTEM_UID) {
+ if (!TelephonyPermissions.isSystemOrPhone(callingUid)) {
throw new SecurityException(
"Cannot call " + methodName + " from UID " + callingUid);
}
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 4d07ab5..8be20b0 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -1637,10 +1637,12 @@
private boolean isSystemOrCertificateMatchingPackage(PackageInfo pi, String cert) {
if (cert == null) {
return pi.applicationInfo.isSystemApp();
+ } else if (Objects.equals(cert, "platform")) {
+ return mServiceInternal.isPlatformSigned(pi.packageName);
+ } else {
+ return mContext.getPackageManager().hasSigningCertificate(pi.packageName, HexEncoding.
+ decode(cert.replace(":", "")), PackageManager.CERT_INPUT_SHA256);
}
-
- return mContext.getPackageManager().hasSigningCertificate(pi.packageName, HexEncoding.
- decode(cert.replace(":", "")), PackageManager.CERT_INPUT_SHA256);
}
private static boolean doesPackageSupportRuntimePermissions(PackageInfo pkg) {
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 2fc183d..bc29b37 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -532,7 +532,8 @@
return false;
}
- if (Flags.keyboardCategoryEnabled() && mVibrationConfig.hasFixedKeyboardAmplitude()) {
+ if (Flags.keyboardCategoryEnabled()
+ && mVibrationConfig.isKeyboardVibrationSettingsSupported()) {
int category = callerInfo.attrs.getCategory();
if (usage == USAGE_TOUCH && category == CATEGORY_KEYBOARD) {
// Keyboard touch has a different user setting.
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index d45ed12..14e256f 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -1335,12 +1335,16 @@
}
// If there is only one adaptor, attach the windowless window to top activity,
// because fixed rotation only applies on activity.
- // Note that embedded activity won't use fixed rotation.
- final Configuration openConfig = mAdaptors.length == 1
+ // Note that embedded activity won't use fixed rotation. Also, there is only one
+ // animation target for closing task.
+ final boolean chooseActivity = mAdaptors.length == 1
+ && (switchType == ACTIVITY_SWITCH || mainActivity.mDisplayContent
+ .isFixedRotationLaunchingApp(mainActivity));
+ final Configuration openConfig = chooseActivity
? mainActivity.getConfiguration() : openTask.getConfiguration();
mRequestedStartingSurfaceId = openTask.mAtmService.mTaskOrganizerController
.addWindowlessStartingSurface(openTask, mainActivity,
- mAdaptors.length == 1 ? mainActivity.getSurfaceControl()
+ chooseActivity ? mainActivity.getSurfaceControl()
: mRemoteAnimationTarget.leash, snapshot, openConfig,
new IWindowlessStartingSurfaceCallback.Stub() {
// Once the starting surface has been created in shell, it will call
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 215cf2c..791d030 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2134,14 +2134,20 @@
}
t.traceEnd();
- t.traceBegin("StartVpnManagerService");
- try {
- vpnManager = VpnManagerService.create(context);
- ServiceManager.addService(Context.VPN_MANAGEMENT_SERVICE, vpnManager);
- } catch (Throwable e) {
- reportWtf("starting VPN Manager Service", e);
+ if (!isWatch || !android.server.Flags.allowRemovingVpnService()) {
+ t.traceBegin("StartVpnManagerService");
+ try {
+ vpnManager = VpnManagerService.create(context);
+ ServiceManager.addService(Context.VPN_MANAGEMENT_SERVICE, vpnManager);
+ } catch (Throwable e) {
+ reportWtf("starting VPN Manager Service", e);
+ }
+ t.traceEnd();
+ } else {
+ // VPN management currently does not work in Wear, so skip starting the
+ // VPN manager SystemService.
+ Slog.i(TAG, "Not starting VpnManagerService");
}
- t.traceEnd();
t.traceBegin("StartVcnManagementService");
try {
diff --git a/services/java/com/android/server/flags.aconfig b/services/java/com/android/server/flags.aconfig
index e8aa68c..29f3871 100644
--- a/services/java/com/android/server/flags.aconfig
+++ b/services/java/com/android/server/flags.aconfig
@@ -21,4 +21,11 @@
namespace: "wear_frameworks"
description: "Remove WearableSensingManagerService on Wear"
bug: "340929916"
+}
+
+flag {
+ name: "allow_removing_vpn_service"
+ namespace: "wear_frameworks"
+ description: "Allow removing VpnManagerService"
+ bug: "340928692"
}
\ No newline at end of file
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
index 80eab11..17d9ef9 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -233,7 +233,7 @@
Process.THREAD_PRIORITY_FOREGROUND,
true /* allowIo */);
mInputMethodManagerService = new InputMethodManagerService(mContext,
- InputMethodManagerService.shouldEnableExperimentalConcurrentMultiUserMode(mContext),
+ InputMethodManagerService.shouldEnableConcurrentMultiUserMode(mContext),
mServiceThread, mIoThread,
unusedUserId -> mMockInputMethodBindingController);
spyOn(mInputMethodManagerService);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index ecd799f..6ec888c 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -406,8 +406,6 @@
mContextInjector.getValue().accept(opContext);
verify(mHal).onContextChanged(same(opContext));
- verify(mHal, times(2)).setIgnoreDisplayTouches(
- opContext.operationState.getFingerprintOperationState().isHardwareIgnoringTouches);
client.stopHalOperation();
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
index 88a9483..60d8964 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -605,7 +605,7 @@
public void shouldIgnoreVibration_withKeyboardSettingsOff_shouldIgnoreKeyboardVibration() {
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_MEDIUM);
setUserSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED, 0 /* OFF*/);
- setHasFixedKeyboardAmplitudeIntensity(true);
+ setKeyboardVibrationSettingsSupported(true);
// Keyboard touch ignored.
assertVibrationIgnoredForAttributes(
@@ -630,7 +630,7 @@
public void shouldIgnoreVibration_withKeyboardSettingsOn_shouldNotIgnoreKeyboardVibration() {
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
setUserSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED, 1 /* ON */);
- setHasFixedKeyboardAmplitudeIntensity(true);
+ setKeyboardVibrationSettingsSupported(true);
// General touch ignored.
assertVibrationIgnoredForUsage(USAGE_TOUCH, Vibration.Status.IGNORED_FOR_SETTINGS);
@@ -645,10 +645,10 @@
@Test
@RequiresFlagsEnabled(Flags.FLAG_KEYBOARD_CATEGORY_ENABLED)
- public void shouldIgnoreVibration_noFixedKeyboardAmplitude_ignoresKeyboardTouchVibration() {
+ public void shouldIgnoreVibration_notSupportKeyboardVibration_ignoresKeyboardTouchVibration() {
setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
setUserSetting(Settings.System.KEYBOARD_VIBRATION_ENABLED, 1 /* ON */);
- setHasFixedKeyboardAmplitudeIntensity(false);
+ setKeyboardVibrationSettingsSupported(false);
// General touch ignored.
assertVibrationIgnoredForUsage(USAGE_TOUCH, Vibration.Status.IGNORED_FOR_SETTINGS);
@@ -974,8 +974,8 @@
when(mVibrationConfigMock.ignoreVibrationsOnWirelessCharger()).thenReturn(ignore);
}
- private void setHasFixedKeyboardAmplitudeIntensity(boolean hasFixedAmplitude) {
- when(mVibrationConfigMock.hasFixedKeyboardAmplitude()).thenReturn(hasFixedAmplitude);
+ private void setKeyboardVibrationSettingsSupported(boolean supported) {
+ when(mVibrationConfigMock.isKeyboardVibrationSettingsSupported()).thenReturn(supported);
}
private void deleteUserSetting(String settingName) {