diff options
183 files changed, 3853 insertions, 2164 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 1d92778a9117..9a4323a119f0 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -25,6 +25,6 @@ hidden_api_txt_checksorted_hook = ${REPO_ROOT}/tools/platform-compat/hiddenapi/c hidden_api_txt_exclude_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/exclude.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT} -ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check -i ${REPO_ROOT}/frameworks/base/ktfmt_includes.txt ${PREUPLOAD_FILES} +ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check -i ${REPO_ROOT}/frameworks/base/packages/SystemUI/ktfmt_includes.txt ${PREUPLOAD_FILES} ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES} diff --git a/core/api/system-current.txt b/core/api/system-current.txt index ef8ae7095d65..a87f2e2bdaee 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -6134,6 +6134,11 @@ package android.media { field public static final int ROLE_OUTPUT = 2; // 0x2 } + public class AudioDeviceVolumeManager { + ctor public AudioDeviceVolumeManager(@NonNull android.content.Context); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolume(@NonNull android.media.VolumeInfo, @NonNull android.media.AudioDeviceAttributes); + } + public final class AudioFocusInfo implements android.os.Parcelable { method public int describeContents(); method @NonNull public android.media.AudioAttributes getAttributes(); @@ -6453,6 +6458,33 @@ package android.media { method public void onSpatializerOutputChanged(@NonNull android.media.Spatializer, @IntRange(from=0) int); } + public final class VolumeInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public static android.media.VolumeInfo getDefaultVolumeInfo(); + method public int getMaxVolumeIndex(); + method public int getMinVolumeIndex(); + method public int getStreamType(); + method @Nullable public android.media.audiopolicy.AudioVolumeGroup getVolumeGroup(); + method public int getVolumeIndex(); + method public boolean hasStreamType(); + method public boolean hasVolumeGroup(); + method public boolean isMuted(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.media.VolumeInfo> CREATOR; + field public static final int INDEX_NOT_SET = -100; // 0xffffff9c + } + + public static final class VolumeInfo.Builder { + ctor public VolumeInfo.Builder(int); + ctor public VolumeInfo.Builder(@NonNull android.media.audiopolicy.AudioVolumeGroup); + ctor public VolumeInfo.Builder(@NonNull android.media.VolumeInfo); + method @NonNull public android.media.VolumeInfo build(); + method @NonNull public android.media.VolumeInfo.Builder setMaxVolumeIndex(int); + method @NonNull public android.media.VolumeInfo.Builder setMinVolumeIndex(int); + method @NonNull public android.media.VolumeInfo.Builder setMuted(boolean); + method @NonNull public android.media.VolumeInfo.Builder setVolumeIndex(int); + } + } package android.media.audiofx { diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index b9ad595778e4..7215987b0d87 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -753,7 +753,7 @@ public final class NotificationChannel implements Parcelable { /** * Returns the vibration pattern for notifications posted to this channel. Will be ignored if - * vibration is not enabled ({@link #shouldVibrate()}. + * vibration is not enabled ({@link #shouldVibrate()}). */ public long[] getVibrationPattern() { return mVibration; diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index bca100a1d81e..20f01ae3ae0d 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -68,6 +68,12 @@ public class FeatureFlagUtils { public static final String SETTINGS_APP_LOCALE_OPT_IN_ENABLED = "settings_app_locale_opt_in_enabled"; + /** + * Launch the Volume panel in SystemUI. + * @hide + */ + public static final String SETTINGS_VOLUME_PANEL_IN_SYSTEMUI = + "settings_volume_panel_in_systemui"; /** @hide */ public static final String SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS = @@ -110,6 +116,12 @@ public class FeatureFlagUtils { */ public static final String SETTINGS_NEW_KEYBOARD_UI = "settings_new_keyboard_ui"; + /** + * Enable the new pages which is implemented with SPA. + * @hide + */ + public static final String SETTINGS_ENABLE_SPA = "settings_enable_spa"; + private static final Map<String, String> DEFAULT_FLAGS; static { @@ -134,6 +146,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_search_always_expand", "true"); DEFAULT_FLAGS.put(SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE, "false"); DEFAULT_FLAGS.put(SETTINGS_APP_LOCALE_OPT_IN_ENABLED, "true"); + DEFAULT_FLAGS.put(SETTINGS_VOLUME_PANEL_IN_SYSTEMUI, "false"); DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true"); DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "true"); DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true"); @@ -141,6 +154,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put(SETTINGS_ENABLE_CLEAR_CALLING, "false"); DEFAULT_FLAGS.put(SETTINGS_ACCESSIBILITY_SIMPLE_CURSOR, "false"); DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_UI, "false"); + DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA, "false"); } private static final Set<String> PERSISTENT_FLAGS; diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 6825f034f5b3..f93b8b7c1b5f 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -226,8 +226,6 @@ public class Editor { final UndoInputFilter mUndoInputFilter = new UndoInputFilter(this); boolean mAllowUndo = true; - private int mLastInputSource = InputDevice.SOURCE_UNKNOWN; - private final MetricsLogger mMetricsLogger = new MetricsLogger(); // Cursor Controllers. @@ -1735,8 +1733,6 @@ public class Editor { public void onTouchEvent(MotionEvent event) { final boolean filterOutEvent = shouldFilterOutTouchEvent(event); - mLastInputSource = event.getSource(); - mLastButtonState = event.getButtonState(); if (filterOutEvent) { if (event.getActionMasked() == MotionEvent.ACTION_UP) { @@ -1789,7 +1785,7 @@ public class Editor { } private void showFloatingToolbar() { - if (mTextActionMode != null && showUIForTouchScreen()) { + if (mTextActionMode != null && mTextView.showUIForTouchScreen()) { // Delay "show" so it doesn't interfere with click confirmations // or double-clicks that could "dismiss" the floating toolbar. int delay = ViewConfiguration.getDoubleTapTimeout(); @@ -1870,7 +1866,7 @@ public class Editor { ? getSelectionController() : getInsertionController(); if (cursorController != null && !cursorController.isActive() && !cursorController.isCursorBeingModified() - && showUIForTouchScreen()) { + && mTextView.showUIForTouchScreen()) { cursorController.show(); } } @@ -2521,7 +2517,7 @@ public class Editor { return false; } - if (!showUIForTouchScreen()) { + if (!mTextView.showUIForTouchScreen()) { return false; } @@ -2677,7 +2673,7 @@ public class Editor { mTextView.postDelayed(mShowSuggestionRunnable, ViewConfiguration.getDoubleTapTimeout()); } else if (hasInsertionController()) { - if (shouldInsertCursor && showUIForTouchScreen()) { + if (shouldInsertCursor && mTextView.showUIForTouchScreen()) { getInsertionController().show(); } else { getInsertionController().hide(); @@ -5408,7 +5404,7 @@ public class Editor { final boolean shouldShow = checkForTransforms() /*check not rotated and compute scale*/ && !tooLargeTextForMagnifier() && obtainMagnifierShowCoordinates(event, showPosInView) - && showUIForTouchScreen(); + && mTextView.showUIForTouchScreen(); if (shouldShow) { // Make the cursor visible and stop blinking. mRenderCursorRegardlessTiming = true; @@ -6354,16 +6350,6 @@ public class Editor { } } - /** - * Returns true when need to show UIs, e.g. floating toolbar, etc, for finger based interaction. - * - * @return true if UIs need to show for finger interaciton. false if UIs are not necessary. - */ - public boolean showUIForTouchScreen() { - return (mLastInputSource & InputDevice.SOURCE_TOUCHSCREEN) - == InputDevice.SOURCE_TOUCHSCREEN; - } - /** Controller for the insertion cursor. */ @VisibleForTesting public class InsertionPointCursorController implements CursorController { diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java index 4ccd77b2713e..be6b08fbddae 100644 --- a/core/java/android/widget/SelectionActionModeHelper.java +++ b/core/java/android/widget/SelectionActionModeHelper.java @@ -301,7 +301,7 @@ public final class SelectionActionModeHelper { final SelectionModifierCursorController controller = mEditor.getSelectionController(); if (controller != null && (mTextView.isTextSelectable() || mTextView.isTextEditable())) { - if (mEditor.showUIForTouchScreen()) { + if (mTextView.showUIForTouchScreen()) { controller.show(); } else { controller.hide(); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 28b83b2068ba..f53dd0c53ef5 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -973,6 +973,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mDeviceProvisionedState = DEVICE_PROVISIONED_UNKNOWN; /** + * The last input source on this TextView. + */ + private int mLastInputSource = InputDevice.SOURCE_UNKNOWN; + + /** * The TextView does not auto-size text (default). */ public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; @@ -11565,6 +11570,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener MotionEvent.actionToString(event.getActionMasked()), event.getX(), event.getY()); } + mLastInputSource = event.getSource(); final int action = event.getActionMasked(); if (mEditor != null) { if (!isFromPrimePointer(event, false)) { @@ -11654,6 +11660,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Returns true when need to show UIs, e.g. floating toolbar, etc, for finger based interaction. + * + * @return true if UIs need to show for finger interaciton. false if UIs are not necessary. + * @hide + */ + public final boolean showUIForTouchScreen() { + return (mLastInputSource & InputDevice.SOURCE_TOUCHSCREEN) + == InputDevice.SOURCE_TOUCHSCREEN; + } + + /** * The fill dialog UI is a more conspicuous and efficient interface than dropdown UI. * If autofill suggestions are available when the user clicks on a field that supports filling * the dialog UI, Autofill will pop up a fill dialog. The dialog will take up a larger area diff --git a/core/java/com/android/internal/widget/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java index b11ea2961c17..9ef7ce38fc09 100644 --- a/core/java/com/android/internal/widget/LocalImageResolver.java +++ b/core/java/com/android/internal/widget/LocalImageResolver.java @@ -19,6 +19,8 @@ package com.android.internal.widget; import android.annotation.DrawableRes; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.ImageDecoder; @@ -109,13 +111,13 @@ public class LocalImageResolver { } break; case Icon.TYPE_RESOURCE: - if (!(TextUtils.isEmpty(icon.getResPackage()) - || context.getPackageName().equals(icon.getResPackage()))) { - // We can't properly resolve icons from other packages here, so fall back. + Resources res = resolveResourcesForIcon(context, icon); + if (res == null) { + // We couldn't resolve resources properly, fall back to icon loading. return icon.loadDrawable(context); } - Drawable result = resolveImage(icon.getResId(), context, maxWidth, maxHeight); + Drawable result = resolveImage(res, icon.getResId(), maxWidth, maxHeight); if (result != null) { return tintDrawable(icon, result); } @@ -159,6 +161,13 @@ public class LocalImageResolver { } @Nullable + private static Drawable resolveImage(Resources res, @DrawableRes int resId, int maxWidth, + int maxHeight) { + final ImageDecoder.Source source = ImageDecoder.createSource(res, resId); + return resolveImage(source, maxWidth, maxHeight); + } + + @Nullable private static Drawable resolveBitmapImage(Icon icon, Context context, int maxWidth, int maxHeight) { @@ -259,4 +268,52 @@ public class LocalImageResolver { } return icon.getUri(); } + + /** + * Resolves the correct resources package for a given Icon - it may come from another + * package. + * + * @see Icon#loadDrawableInner(Context) + * @hide + * + * @return resources instance if the operation succeeded, null otherwise + */ + @Nullable + @VisibleForTesting + public static Resources resolveResourcesForIcon(Context context, Icon icon) { + if (icon.getType() != Icon.TYPE_RESOURCE) { + return null; + } + + // Icons cache resolved resources, use cache if available. + Resources res = icon.getResources(); + if (res != null) { + return res; + } + + String resPackage = icon.getResPackage(); + // No package means we try to use current context. + if (TextUtils.isEmpty(resPackage) || context.getPackageName().equals(resPackage)) { + return context.getResources(); + } + + if ("android".equals(resPackage)) { + return Resources.getSystem(); + } + + final PackageManager pm = context.getPackageManager(); + try { + ApplicationInfo ai = pm.getApplicationInfo(resPackage, + PackageManager.MATCH_UNINSTALLED_PACKAGES + | PackageManager.GET_SHARED_LIBRARY_FILES); + if (ai != null) { + return pm.getResourcesForApplication(ai); + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, String.format("Unable to resolve package %s for icon %s", resPackage, icon)); + return null; + } + + return null; + } } diff --git a/core/jni/OWNERS b/core/jni/OWNERS index 7f50204fb842..14699e7097f4 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -95,3 +95,7 @@ per-file android_os_VintfRuntimeInfo* = file:platform/system/libvintf:/OWNERS # Battery per-file com_android_internal_os_Kernel* = file:/BATTERY_STATS_OWNERS per-file com_android_internal_os_*MultiStateCounter* = file:/BATTERY_STATS_OWNERS + +# PM +per-file com_android_internal_content_* = file:/PACKAGE_MANAGER_OWNERS + diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 6a52ec91fa32..e7cae76c60fc 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1565,7 +1565,8 @@ <bool name="config_enableIdleScreenBrightnessMode">false</bool> <!-- Array of desired screen brightness in nits corresponding to the lux values - in the config_autoBrightnessLevels array. The display brightness is defined as the measured + in the config_autoBrightnessLevels array. As with config_screenBrightnessMinimumNits and + config_screenBrightnessMaximumNits, the display brightness is defined as the measured brightness of an all-white image. If this is defined then: @@ -1586,7 +1587,7 @@ <array name="config_autoBrightnessDisplayValuesNitsIdle"> </array> - <!-- Array of output values for button backlight corresponding to the lux values + <!-- Array of output values for button backlight corresponding to the luX values in the config_autoBrightnessLevels array. This array should have size one greater than the size of the config_autoBrightnessLevels array. The brightness values must be between 0 and 255 and be non-decreasing. diff --git a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java index 0cee526651a6..271a20b71106 100644 --- a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java +++ b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java @@ -17,6 +17,8 @@ package com.android.internal.widget; import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.Resources; import android.graphics.BitmapFactory; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; @@ -279,4 +281,49 @@ public class LocalImageResolverTest { // This drawable must not be loaded - if it was, the code ignored the package specification. assertThat(d).isNull(); } + + @Test + public void resolveResourcesForIcon_notAResourceIcon_returnsNull() { + Icon icon = Icon.createWithContentUri(Uri.parse("some_uri")); + assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isNull(); + } + + @Test + public void resolveResourcesForIcon_localPackageIcon_returnsPackageResources() { + Icon icon = Icon.createWithResource(mContext, R.drawable.test32x24); + assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)) + .isSameInstanceAs(mContext.getResources()); + } + + @Test + public void resolveResourcesForIcon_iconWithoutPackageSpecificed_returnsPackageResources() { + Icon icon = Icon.createWithResource("", R.drawable.test32x24); + assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)) + .isSameInstanceAs(mContext.getResources()); + } + + @Test + public void resolveResourcesForIcon_systemPackageSpecified_returnsSystemPackage() { + Icon icon = Icon.createWithResource("android", R.drawable.test32x24); + assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isSameInstanceAs( + Resources.getSystem()); + } + + @Test + public void resolveResourcesForIcon_differentPackageSpecified_returnsPackageResources() throws + PackageManager.NameNotFoundException { + String pkg = "com.android.settings"; + Resources res = mContext.getPackageManager().getResourcesForApplication(pkg); + int resId = res.getIdentifier("ic_android", "drawable", pkg); + Icon icon = Icon.createWithResource(pkg, resId); + + assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon).getDrawable(resId, + mContext.getTheme())).isNotNull(); + } + + @Test + public void resolveResourcesForIcon_invalidPackageSpecified_returnsNull() { + Icon icon = Icon.createWithResource("invalid.package", R.drawable.test32x24); + assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isNull(); + } } diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml index f030d80a3533..e0e13f59b706 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -81,5 +81,6 @@ <permission name="android.permission.READ_DEVICE_CONFIG" /> <permission name="android.permission.READ_SAFETY_CENTER_STATUS" /> <permission name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" /> + <permission name="android.permission.READ_SEARCH_INDEXABLES" /> </privapp-permissions> </permissions> diff --git a/ktfmt_includes.txt b/ktfmt_includes.txt deleted file mode 100644 index c7062e093135..000000000000 --- a/ktfmt_includes.txt +++ /dev/null @@ -1,17 +0,0 @@ -packages/SystemUI/compose/ -packages/SystemUI/screenshot/ -packages/SystemUI/src/com/android/systemui/people/data -packages/SystemUI/src/com/android/systemui/people/ui -packages/SystemUI/src/com/android/systemui/keyguard/data -packages/SystemUI/src/com/android/systemui/keyguard/dagger -packages/SystemUI/src/com/android/systemui/keyguard/domain -packages/SystemUI/src/com/android/systemui/keyguard/shared -packages/SystemUI/src/com/android/systemui/keyguard/ui -packages/SystemUI/src/com/android/systemui/qs/footer -packages/SystemUI/src/com/android/systemui/security -packages/SystemUI/src/com/android/systemui/common/ -packages/SystemUI/tests/utils/src/com/android/systemui/qs/ -packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt -packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeUserInfoController.kt -packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/MockUserSwitcherControllerWrapper.kt -packages/SystemUI/tests/src/com/android/systemui/qs/footer/
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java index 0d75bc451b72..f1465f421c5b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java @@ -105,8 +105,8 @@ public class FullscreenTaskListener<T extends AutoCloseable> state.mTaskInfo = taskInfo; mTasks.put(taskInfo.taskId, state); - updateRecentsForVisibleFullscreenTask(taskInfo); if (Transitions.ENABLE_SHELL_TRANSITIONS) return; + updateRecentsForVisibleFullscreenTask(taskInfo); if (shouldShowWindowDecor(taskInfo) && mWindowDecorViewModelOptional.isPresent()) { SurfaceControl.Transaction t = new SurfaceControl.Transaction(); state.mWindowDecoration = @@ -135,8 +135,8 @@ public class FullscreenTaskListener<T extends AutoCloseable> mWindowDecorViewModelOptional.get().onTaskInfoChanged( state.mTaskInfo, state.mWindowDecoration); } - updateRecentsForVisibleFullscreenTask(taskInfo); if (Transitions.ENABLE_SHELL_TRANSITIONS) return; + updateRecentsForVisibleFullscreenTask(taskInfo); final Point positionInParent = state.mTaskInfo.positionInParent; if (!oldPositionInParent.equals(state.mTaskInfo.positionInParent)) { diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt index 67d7aca8db8c..298bf68c41a7 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt @@ -86,8 +86,7 @@ abstract class BaseBubbleScreen( @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 3) + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0)) } const val FIND_OBJECT_TIMEOUT = 2000L diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt index 293eb7cd5581..47557bcead2f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt @@ -18,7 +18,6 @@ package com.android.wm.shell.flicker.bubble import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Postsubmit -import android.platform.test.annotations.Presubmit import android.view.WindowInsets import android.view.WindowManager import androidx.test.filters.RequiresDevice @@ -92,7 +91,7 @@ class LaunchBubbleFromLockScreen(testSpec: FlickerTestParameter) : BaseBubbleScr } } - @Presubmit + @FlakyTest(bugId = 242088970) @Test fun testAppIsVisibleAtEnd() { testSpec.assertLayersEnd { @@ -125,7 +124,7 @@ class LaunchBubbleFromLockScreen(testSpec: FlickerTestParameter) : BaseBubbleScr super.navBarWindowIsAlwaysVisible() /** {@inheritDoc} */ - @Postsubmit + @FlakyTest(bugId = 242088970) @Test override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd() @@ -135,4 +134,28 @@ class LaunchBubbleFromLockScreen(testSpec: FlickerTestParameter) : BaseBubbleScr @Test override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible() + + /** {@inheritDoc} */ + @FlakyTest(bugId = 242088970) + @Test + override fun statusBarLayerIsVisibleAtStartAndEnd() = + super.statusBarLayerIsVisibleAtStartAndEnd() + + /** {@inheritDoc} */ + @FlakyTest(bugId = 242088970) + @Test + override fun statusBarLayerPositionAtStartAndEnd() = + super.statusBarLayerPositionAtStartAndEnd() + + /** {@inheritDoc} */ + @FlakyTest(bugId = 242088970) + @Test + override fun statusBarWindowIsAlwaysVisible() = + super.statusBarWindowIsAlwaysVisible() + + /** {@inheritDoc} */ + @FlakyTest(bugId = 242088970) + @Test + override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = + super.visibleWindowsShownMoreThanOneConsecutiveEntry() } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt index d194472b9000..6fcd17ae5f8a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt @@ -185,8 +185,7 @@ open class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 3 + supportedRotations = listOf(Surface.ROTATION_0) ) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt index 507562b00f4f..a99439e35291 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt @@ -246,8 +246,7 @@ class EnterPipToOtherOrientationTest( fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 3 + supportedRotations = listOf(Surface.ROTATION_0) ) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt index b5a3c78b67a7..39a7017a16d0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt @@ -100,7 +100,7 @@ class ExitPipViaExpandButtonClickTest( @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3) + supportedRotations = listOf(Surface.ROTATION_0)) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt index 1d266140f2e6..421a6fc38e4c 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt @@ -125,7 +125,7 @@ class ExitPipViaIntentTest(testSpec: FlickerTestParameter) : ExitPipToAppTransit @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3) + supportedRotations = listOf(Surface.ROTATION_0)) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt index b71a9d85d8cc..3bffef0ca793 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt @@ -86,8 +86,7 @@ class ExitPipWithDismissButtonTest(testSpec: FlickerTestParameter) : ExitPipTran @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 3) + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0)) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt index 31a39c190dd6..75d25e6ef67e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt @@ -105,8 +105,7 @@ class ExitPipWithSwipeDownTest(testSpec: FlickerTestParameter) : ExitPipTransiti @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 3) + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0)) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt index fd661cfc3ee1..825aca3aaa16 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt @@ -178,8 +178,7 @@ class ExpandPipOnDoubleClickTest(testSpec: FlickerTestParameter) : PipTransition fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 3 + supportedRotations = listOf(Surface.ROTATION_0) ) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt index b3f0fb91ab73..d3e2ce1571b4 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt @@ -89,7 +89,7 @@ open class MovePipDownShelfHeightChangeTest( @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3 + supportedRotations = listOf(Surface.ROTATION_0) ) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt index 8bd5c548f6bd..3d64bbeb720b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt @@ -105,7 +105,7 @@ class MovePipUpShelfHeightChangeTest( @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3 + supportedRotations = listOf(Surface.ROTATION_0) ) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt index 454927e57aa2..be39faeff321 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt @@ -116,8 +116,7 @@ open class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testS @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 3) + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0)) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt index 09248a167308..4dc98588217a 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt @@ -264,8 +264,7 @@ open class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testS @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigRotationTests( - supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90), - repetitions = 3 + supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90) ) } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt index 6d64cb9e0dee..d5de22fb49c0 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt @@ -224,8 +224,7 @@ open class SetRequestedOrientationWhilePinnedTest( @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0), - repetitions = 1) + .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0)) } } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt index d23881475ad6..6cbb685850fa 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt @@ -178,7 +178,6 @@ class CopyContentInSplit(testSpec: FlickerTestParameter) : SplitScreenBase(testS @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy. supportedNavigationModes = listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt index ba40c2740bb1..581826ef889f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt @@ -195,7 +195,6 @@ class DismissSplitScreenByDivider (testSpec: FlickerTestParameter) : SplitScreen @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy. supportedNavigationModes = listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt index 6828589656d6..5c051e859d59 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt @@ -182,7 +182,6 @@ class DismissSplitScreenByGoHome( @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy. supportedNavigationModes = listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt index 9ac7c230096b..9ca9ab01fd7b 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt @@ -186,7 +186,6 @@ class DragDividerToResize (testSpec: FlickerTestParameter) : SplitScreenBase(tes @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, supportedRotations = listOf(Surface.ROTATION_0), // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy. supportedNavigationModes = diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt index 8401c1a910b8..8e2769fb75bd 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt @@ -180,7 +180,6 @@ class EnterSplitScreenByDragFromAllApps( @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy. supportedNavigationModes = listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt index 168afda119a9..531d376e3588 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt @@ -195,7 +195,6 @@ class EnterSplitScreenByDragFromNotification( @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy. supportedNavigationModes = listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt index c1fce5f40b57..ea43c7ea0ddf 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt @@ -183,7 +183,6 @@ class EnterSplitScreenByDragFromTaskbar( @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, supportedNavigationModes = listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY) ) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt index 153056188d24..525e09a19d2f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt @@ -180,7 +180,6 @@ class SwitchAppByDoubleTapDivider (testSpec: FlickerTestParameter) : SplitScreen @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy. supportedNavigationModes = listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt index 20544bd2fc2f..c030603a6b55 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt @@ -184,7 +184,6 @@ class SwitchBackToSplitFromAnotherApp(testSpec: FlickerTestParameter) : SplitScr @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy. supportedNavigationModes = listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt index 5a8604f2dccc..b8565f3e89b2 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt @@ -183,7 +183,6 @@ class SwitchBackToSplitFromHome(testSpec: FlickerTestParameter) : SplitScreenBas @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy. supportedNavigationModes = listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)) diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt index adea66a49c46..20d7f2cf57e8 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt @@ -185,7 +185,6 @@ class SwitchBackToSplitFromRecent(testSpec: FlickerTestParameter) : SplitScreenB @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests( - repetitions = SplitScreenHelper.TEST_REPETITIONS, // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy. supportedNavigationModes = listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)) diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java index c70887672f9e..40f6dc541f86 100644 --- a/media/java/android/media/AudioDeviceVolumeManager.java +++ b/media/java/android/media/AudioDeviceVolumeManager.java @@ -21,6 +21,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.content.Context; import android.os.IBinder; import android.os.RemoteException; @@ -39,23 +41,29 @@ import java.util.concurrent.Executor; * @hide * AudioDeviceVolumeManager provides access to audio device volume control. */ +@SystemApi public class AudioDeviceVolumeManager { // define when using Log.* //private static final String TAG = "AudioDeviceVolumeManager"; - /** Indicates no special treatment in the handling of the volume adjustment */ + /** @hide + * Indicates no special treatment in the handling of the volume adjustment */ public static final int ADJUST_MODE_NORMAL = 0; - /** Indicates the start of a volume adjustment */ + /** @hide + * Indicates the start of a volume adjustment */ public static final int ADJUST_MODE_START = 1; - /** Indicates the end of a volume adjustment */ + /** @hide + * Indicates the end of a volume adjustment */ public static final int ADJUST_MODE_END = 2; + /** @hide */ @IntDef(flag = false, prefix = "ADJUST_MODE", value = { ADJUST_MODE_NORMAL, ADJUST_MODE_START, ADJUST_MODE_END} ) + /** @hide */ @Retention(RetentionPolicy.SOURCE) public @interface VolumeAdjustmentMode {} @@ -64,7 +72,16 @@ public class AudioDeviceVolumeManager { private final @NonNull String mPackageName; private final @Nullable String mAttributionTag; - public AudioDeviceVolumeManager(Context context) { + /** + * Constructor + * @param context the Context for the device volume operations + */ + @SuppressLint("ManagerConstructor") + // reason for suppression: even though the functionality handled by this class is implemented in + // AudioService, we want to avoid bloating android.media.AudioManager + // with @SystemApi functionality + public AudioDeviceVolumeManager(@NonNull Context context) { + Objects.requireNonNull(context); mPackageName = context.getApplicationContext().getOpPackageName(); mAttributionTag = context.getApplicationContext().getAttributionTag(); } @@ -101,6 +118,7 @@ public class AudioDeviceVolumeManager { @VolumeAdjustmentMode int mode); } + /** @hide */ static class ListenerInfo { final @NonNull OnAudioDeviceVolumeChangedListener mListener; final @NonNull Executor mExecutor; @@ -127,6 +145,7 @@ public class AudioDeviceVolumeManager { @GuardedBy("mDeviceVolumeListenerLock") private DeviceVolumeDispatcherStub mDeviceVolumeDispatcherStub; + /** @hide */ final class DeviceVolumeDispatcherStub extends IAudioDeviceVolumeDispatcher.Stub { /** * Register / unregister the stub @@ -305,6 +324,7 @@ public class AudioDeviceVolumeManager { * @param vi the volume information, only stream-based volumes are supported * @param ada the device for which volume is to be modified */ + @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolume(@NonNull VolumeInfo vi, @NonNull AudioDeviceAttributes ada) { try { @@ -315,6 +335,7 @@ public class AudioDeviceVolumeManager { } /** + * @hide * Return human-readable name for volume behavior * @param behavior one of the volume behaviors defined in AudioManager * @return a string for the given behavior diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 650f36059495..72190e370129 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -65,8 +65,6 @@ public class AudioSystem private static final String TAG = "AudioSystem"; - private static final int SOURCE_CODEC_TYPE_OPUS = 6; // TODO remove in U - // private constructor to prevent instantiating AudioSystem private AudioSystem() { throw new UnsupportedOperationException("Trying to instantiate AudioSystem"); @@ -293,7 +291,7 @@ public class AudioSystem case AUDIO_FORMAT_APTX_HD: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD; case AUDIO_FORMAT_LDAC: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC; case AUDIO_FORMAT_LC3: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_LC3; - case AUDIO_FORMAT_OPUS: return SOURCE_CODEC_TYPE_OPUS; // TODO update in U + case AUDIO_FORMAT_OPUS: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS; default: Log.e(TAG, "Unknown audio format 0x" + Integer.toHexString(audioFormat) + " for conversion to BT codec"); @@ -336,7 +334,7 @@ public class AudioSystem return AudioSystem.AUDIO_FORMAT_LDAC; case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LC3: return AudioSystem.AUDIO_FORMAT_LC3; - case SOURCE_CODEC_TYPE_OPUS: // TODO update in U + case BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS: return AudioSystem.AUDIO_FORMAT_OPUS; default: Log.e(TAG, "Unknown BT codec 0x" + Integer.toHexString(btCodec) diff --git a/media/java/android/media/VolumeInfo.java b/media/java/android/media/VolumeInfo.java index c61b0e57db1a..6b4f604025e2 100644 --- a/media/java/android/media/VolumeInfo.java +++ b/media/java/android/media/VolumeInfo.java @@ -18,6 +18,7 @@ package android.media; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.content.Context; import android.media.audiopolicy.AudioVolumeGroup; import android.os.IBinder; @@ -32,16 +33,13 @@ import java.util.Objects; /** * @hide - * A class to represent type of volume information. + * A class to represent volume information. * Can be used to represent volume associated with a stream type or {@link AudioVolumeGroup}. * Volume index is optional when used to represent a category of volume. * Index ranges are supported too, making the representation of volume changes agnostic to the * range (e.g. can be used to map BT A2DP absolute volume range to internal range). - * - * Note: this class is not yet part of the SystemApi but is intended to be gradually introduced - * particularly in parts of the audio framework that suffer from code ambiguity when - * dealing with different volume ranges / units. */ +@SystemApi public final class VolumeInfo implements Parcelable { private static final String TAG = "VolumeInfo"; diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl index 31fb8d03c4a0..9bf126b7a875 100644 --- a/media/java/android/media/session/ISession.aidl +++ b/media/java/android/media/session/ISession.aidl @@ -35,7 +35,7 @@ interface ISession { ISessionController getController(); void setFlags(int flags); void setActive(boolean active); - void setMediaButtonReceiver(in PendingIntent mbr); + void setMediaButtonReceiver(in PendingIntent mbr, String sessionPackageName); void setMediaButtonBroadcastReceiver(in ComponentName broadcastReceiver); void setLaunchPendingIntent(in PendingIntent pi); void destroySession(); diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 1bd12afdc026..9e265d8339dd 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -286,7 +286,7 @@ public final class MediaSession { @Deprecated public void setMediaButtonReceiver(@Nullable PendingIntent mbr) { try { - mBinder.setMediaButtonReceiver(mbr); + mBinder.setMediaButtonReceiver(mbr, mContext.getPackageName()); } catch (RemoteException e) { Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e); } diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt index e300624bcc95..3f375345f30f 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/SpaEnvironment.kt @@ -24,6 +24,7 @@ import com.android.settingslib.spa.gallery.page.PreferencePageProvider import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider import com.android.settingslib.spa.gallery.page.SliderPageProvider import com.android.settingslib.spa.gallery.page.SwitchPreferencePageProvider +import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider val galleryPageProviders = SettingsPageProviderRepository( allPagesList = listOf( @@ -32,6 +33,7 @@ val galleryPageProviders = SettingsPageProviderRepository( SwitchPreferencePageProvider, ArgumentPageProvider, SliderPageProvider, + SpinnerPageProvider, SettingsPagerPageProvider, FooterPageProvider, ), diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt index a85ee2a2a309..089920c8e8cf 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt @@ -29,6 +29,7 @@ import com.android.settingslib.spa.gallery.page.PreferencePageProvider import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider import com.android.settingslib.spa.gallery.page.SliderPageProvider import com.android.settingslib.spa.gallery.page.SwitchPreferencePageProvider +import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider import com.android.settingslib.spa.widget.scaffold.HomeScaffold object HomePageProvider : SettingsPageProvider { @@ -48,6 +49,7 @@ private fun HomePage() { ArgumentPageProvider.EntryItem(stringParam = "foo", intParam = 0) SliderPageProvider.EntryItem() + SpinnerPageProvider.EntryItem() SettingsPagerPageProvider.EntryItem() FooterPageProvider.EntryItem() } diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt index 314635176889..130cbd9f7b7b 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt @@ -30,11 +30,11 @@ import androidx.compose.ui.tooling.preview.Preview import com.android.settingslib.spa.framework.common.SettingsPageProvider import com.android.settingslib.spa.framework.compose.navigator import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.widget.SettingsSlider +import com.android.settingslib.spa.widget.SettingsSliderModel import com.android.settingslib.spa.widget.preference.Preference import com.android.settingslib.spa.widget.preference.PreferenceModel import com.android.settingslib.spa.widget.scaffold.RegularScaffold -import com.android.settingslib.spa.widget.ui.SettingsSlider -import com.android.settingslib.spa.widget.ui.SettingsSliderModel private const val TITLE = "Sample Slider" diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt new file mode 100644 index 000000000000..7efa85b4ad78 --- /dev/null +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2022 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.settingslib.spa.gallery.ui + +import android.os.Bundle +import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.tooling.preview.Preview +import com.android.settingslib.spa.framework.common.SettingsPageProvider +import com.android.settingslib.spa.framework.compose.navigator +import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel +import com.android.settingslib.spa.widget.scaffold.RegularScaffold +import com.android.settingslib.spa.widget.ui.Spinner + +private const val TITLE = "Sample Spinner" + +object SpinnerPageProvider : SettingsPageProvider { + override val name = "Spinner" + + @Composable + override fun Page(arguments: Bundle?) { + SpinnerPage() + } + + @Composable + fun EntryItem() { + Preference(object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + }) + } +} + +@Composable +private fun SpinnerPage() { + RegularScaffold(title = TITLE) { + val selectedIndex = rememberSaveable { mutableStateOf(0) } + Spinner( + options = (1..3).map { "Option $it" }, + selectedIndex = selectedIndex.value, + setIndex = { selectedIndex.value = it }, + ) + Preference(object : PreferenceModel { + override val title = "Selected index" + override val summary = remember { derivedStateOf { selectedIndex.value.toString() } } + }) + } +} + +@Preview(showBackground = true) +@Composable +private fun SpinnerPagePreview() { + SettingsTheme { + SpinnerPage() + } +} diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt index 6a7b17ab1b27..e8d1ea2c7680 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt @@ -21,6 +21,8 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect +import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController @@ -46,12 +48,11 @@ open class BrowseActivity( @Composable private fun MainContent() { - val startDestination = - intent?.getStringExtra(KEY_START_DESTINATION) ?: sppRepository.getDefaultStartPageName() + val destination = intent?.getStringExtra(KEY_DESTINATION) val navController = rememberNavController() CompositionLocalProvider(navController.localNavController()) { - NavHost(navController, startDestination) { + NavHost(navController, sppRepository.getDefaultStartPageName()) { for (page in sppRepository.getAllProviders()) { composable( route = page.route, @@ -61,6 +62,16 @@ open class BrowseActivity( } } } + + if (!destination.isNullOrEmpty()) { + LaunchedEffect(Unit) { + navController.navigate(destination) { + popUpTo(navController.graph.findStartDestination().id) { + inclusive = true + } + } + } + } } } @@ -68,6 +79,6 @@ open class BrowseActivity( get() = name + arguments.joinToString("") { argument -> "/{${argument.name}}" } companion object { - const val KEY_START_DESTINATION = "spa:SpaActivity:startDestination" + const val KEY_DESTINATION = "spa:SpaActivity:destination" } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavControllerWrapper.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavControllerWrapper.kt index c68d5de0d7c7..32ef0bb3d19b 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavControllerWrapper.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavControllerWrapper.kt @@ -16,25 +16,35 @@ package com.android.settingslib.spa.framework.compose +import androidx.activity.OnBackPressedDispatcher +import androidx.activity.compose.LocalOnBackPressedDispatcherOwner import androidx.compose.runtime.Composable +import androidx.compose.runtime.ProvidedValue import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.remember import androidx.navigation.NavHostController interface NavControllerWrapper { fun navigate(route: String) - fun navigateUp() + fun navigateBack() } @Composable -fun NavHostController.localNavController() = - LocalNavController provides remember { NavControllerWrapperImpl(this) } +fun NavHostController.localNavController(): ProvidedValue<NavControllerWrapper> { + val onBackPressedDispatcherOwner = LocalOnBackPressedDispatcherOwner.current + return LocalNavController provides remember { + NavControllerWrapperImpl( + navController = this, + onBackPressedDispatcher = onBackPressedDispatcherOwner?.onBackPressedDispatcher, + ) + } +} val LocalNavController = compositionLocalOf<NavControllerWrapper> { object : NavControllerWrapper { override fun navigate(route: String) {} - override fun navigateUp() {} + override fun navigateBack() {} } } @@ -46,12 +56,13 @@ fun navigator(route: String): () -> Unit { internal class NavControllerWrapperImpl( private val navController: NavHostController, + private val onBackPressedDispatcher: OnBackPressedDispatcher?, ) : NavControllerWrapper { override fun navigate(route: String) { navController.navigate(route) } - override fun navigateUp() { - navController.navigateUp() + override fun navigateBack() { + onBackPressedDispatcher?.onBackPressed() } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt index 27fdc916a434..bc316f71cf23 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt @@ -31,6 +31,10 @@ data class SettingsColorScheme( val secondaryText: Color = Color.Unspecified, val primaryContainer: Color = Color.Unspecified, val onPrimaryContainer: Color = Color.Unspecified, + val spinnerHeaderContainer: Color = Color.Unspecified, + val onSpinnerHeaderContainer: Color = Color.Unspecified, + val spinnerItemContainer: Color = Color.Unspecified, + val onSpinnerItemContainer: Color = Color.Unspecified, ) internal val LocalColorScheme = staticCompositionLocalOf { SettingsColorScheme() } @@ -65,6 +69,10 @@ private fun dynamicLightColorScheme(context: Context): SettingsColorScheme { secondaryText = tonalPalette.neutralVariant30, primaryContainer = tonalPalette.primary90, onPrimaryContainer = tonalPalette.neutral10, + spinnerHeaderContainer = tonalPalette.primary90, + onSpinnerHeaderContainer = tonalPalette.neutral10, + spinnerItemContainer = tonalPalette.secondary90, + onSpinnerItemContainer = tonalPalette.neutralVariant30, ) } @@ -87,5 +95,9 @@ private fun dynamicDarkColorScheme(context: Context): SettingsColorScheme { secondaryText = tonalPalette.neutralVariant80, primaryContainer = tonalPalette.secondary90, onPrimaryContainer = tonalPalette.neutral10, + spinnerHeaderContainer = tonalPalette.primary90, + onSpinnerHeaderContainer = tonalPalette.neutral10, + spinnerItemContainer = tonalPalette.secondary90, + onSpinnerItemContainer = tonalPalette.neutralVariant30, ) } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/SettingsSlider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/SettingsSlider.kt index 0454ac37cfb7..4f77a89577ea 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/SettingsSlider.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/SettingsSlider.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settingslib.spa.widget.ui +package com.android.settingslib.spa.widget import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.AccessAlarm diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt index c9602543b364..b8e43609708d 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt @@ -26,13 +26,13 @@ import androidx.compose.ui.res.stringResource import com.android.settingslib.spa.framework.compose.LocalNavController @Composable -internal fun NavigateUp() { +internal fun NavigateBack() { val navController = LocalNavController.current val contentDescription = stringResource( id = androidx.appcompat.R.string.abc_action_bar_up_description, ) BackAction(contentDescription) { - navController.navigateUp() + navController.navigateBack() } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt index ee453f246623..8b530b0d7b9b 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt @@ -49,7 +49,7 @@ fun SettingsScaffold( modifier = Modifier.padding(SettingsDimension.itemPaddingAround), ) }, - navigationIcon = { NavigateUp() }, + navigationIcon = { NavigateBack() }, actions = actions, colors = settingsTopAppBarColors(), ) diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt new file mode 100644 index 000000000000..429b81a04659 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2022 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.settingslib.spa.widget.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.selection.selectableGroup +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.ArrowDropDown +import androidx.compose.material.icons.outlined.ArrowDropUp +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.unit.dp +import com.android.settingslib.spa.framework.theme.SettingsDimension +import com.android.settingslib.spa.framework.theme.SettingsTheme + +@Composable +fun Spinner(options: List<String>, selectedIndex: Int, setIndex: (index: Int) -> Unit) { + if (options.isEmpty()) { + return + } + + var expanded by rememberSaveable { mutableStateOf(false) } + + Box( + modifier = Modifier + .padding(SettingsDimension.itemPadding) + .selectableGroup(), + ) { + val contentPadding = PaddingValues(horizontal = SettingsDimension.itemPaddingEnd) + Button( + onClick = { expanded = true }, + modifier = Modifier.height(36.dp), + colors = ButtonDefaults.buttonColors( + containerColor = SettingsTheme.colorScheme.spinnerHeaderContainer, + contentColor = SettingsTheme.colorScheme.onSpinnerHeaderContainer, + ), + contentPadding = contentPadding, + ) { + SpinnerText(options[selectedIndex]) + Icon( + imageVector = when { + expanded -> Icons.Outlined.ArrowDropUp + else -> Icons.Outlined.ArrowDropDown + }, + contentDescription = null, + ) + } + DropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + modifier = Modifier.background(SettingsTheme.colorScheme.spinnerItemContainer), + offset = DpOffset(x = 0.dp, y = 4.dp), + ) { + options.forEachIndexed { index, option -> + DropdownMenuItem( + text = { + SpinnerText( + text = option, + modifier = Modifier.padding(end = 24.dp), + color = SettingsTheme.colorScheme.onSpinnerItemContainer, + ) + }, + onClick = { + expanded = false + setIndex(index) + }, + contentPadding = contentPadding, + ) + } + } + } +} + +@Composable +private fun SpinnerText( + text: String, + modifier: Modifier = Modifier, + color: Color = Color.Unspecified, +) { + Text( + text = text, + modifier = modifier.padding(end = SettingsDimension.itemPaddingEnd), + color = color, + style = MaterialTheme.typography.labelLarge, + ) +} + +@Preview(showBackground = true) +@Composable +private fun SpinnerPreview() { + SettingsTheme { + var selectedIndex by rememberSaveable { mutableStateOf(0) } + Spinner( + options = (1..3).map { "Option $it" }, + selectedIndex = selectedIndex, + setIndex = { selectedIndex = it }, + ) + } +} diff --git a/packages/SettingsLib/Spa/tests/Android.bp b/packages/SettingsLib/Spa/tests/Android.bp index 037d8c4e78b1..1ce49fa520b9 100644 --- a/packages/SettingsLib/Spa/tests/Android.bp +++ b/packages/SettingsLib/Spa/tests/Android.bp @@ -31,6 +31,7 @@ android_test { "androidx.compose.runtime_runtime", "androidx.compose.ui_ui-test-junit4", "androidx.compose.ui_ui-test-manifest", + "truth-prebuilt", ], kotlincflags: ["-Xjvm-default=all"], } diff --git a/packages/SettingsLib/Spa/tests/build.gradle b/packages/SettingsLib/Spa/tests/build.gradle index be5a5ec40c4f..5f93a9f4e4b5 100644 --- a/packages/SettingsLib/Spa/tests/build.gradle +++ b/packages/SettingsLib/Spa/tests/build.gradle @@ -63,5 +63,6 @@ dependencies { androidTestImplementation(project(":spa")) androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.3' androidTestImplementation("androidx.compose.ui:ui-test-junit4:$jetpack_compose_version") + androidTestImplementation 'com.google.truth:truth:1.1.3' androidTestDebugImplementation "androidx.compose.ui:ui-test-manifest:$jetpack_compose_version" } diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/SettingsSliderTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/SettingsSliderTest.kt new file mode 100644 index 000000000000..1d95e3383b51 --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/SettingsSliderTest.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 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.settingslib.spa.widget + +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SettingsSliderTest { + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun title_displayed() { + composeTestRule.setContent { + SettingsSlider(object : SettingsSliderModel { + override val title = "Slider" + override val initValue = 40 + }) + } + + composeTestRule.onNodeWithText("Slider").assertIsDisplayed() + } + + // TODO: Add more unit tests for SettingsSlider widget. +} diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/SpinnerTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/SpinnerTest.kt new file mode 100644 index 000000000000..6c56d63c18c7 --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/SpinnerTest.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 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.settingslib.spa.widget.ui + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SpinnerTest { + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun spinner_initialState() { + var selectedIndex by mutableStateOf(0) + composeTestRule.setContent { + Spinner( + options = (1..3).map { "Option $it" }, + selectedIndex = selectedIndex, + setIndex = { selectedIndex = it }, + ) + } + + composeTestRule.onNodeWithText("Option 1").assertIsDisplayed() + composeTestRule.onNodeWithText("Option 2").assertDoesNotExist() + assertThat(selectedIndex).isEqualTo(0) + } + + @Test + fun spinner_canChangeState() { + var selectedIndex by mutableStateOf(0) + composeTestRule.setContent { + Spinner( + options = (1..3).map { "Option $it" }, + selectedIndex = selectedIndex, + setIndex = { selectedIndex = it }, + ) + } + + composeTestRule.onNodeWithText("Option 1").performClick() + composeTestRule.onNodeWithText("Option 2").performClick() + + composeTestRule.onNodeWithText("Option 1").assertDoesNotExist() + composeTestRule.onNodeWithText("Option 2").assertIsDisplayed() + assertThat(selectedIndex).isEqualTo(1) + } +} diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt index dac79a0fbb16..eb9ce5e77c93 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt @@ -30,7 +30,6 @@ import androidx.navigation.NavType import androidx.navigation.navArgument import com.android.settingslib.spa.framework.common.SettingsPageProvider import com.android.settingslib.spa.framework.compose.navigator -import com.android.settingslib.spa.framework.compose.rememberContext import com.android.settingslib.spa.widget.preference.SwitchPreference import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel import com.android.settingslib.spaprivileged.model.app.AppRecord @@ -44,7 +43,7 @@ private const val PACKAGE_NAME = "packageName" private const val USER_ID = "userId" internal class TogglePermissionAppInfoPageProvider( - private val factory: TogglePermissionAppListModelFactory, + private val appListTemplate: TogglePermissionAppListTemplate, ) : SettingsPageProvider { override val name = NAME @@ -57,10 +56,10 @@ internal class TogglePermissionAppInfoPageProvider( @Composable override fun Page(arguments: Bundle?) { checkNotNull(arguments) - val permission = checkNotNull(arguments.getString(PERMISSION)) + val permissionType = checkNotNull(arguments.getString(PERMISSION)) val packageName = checkNotNull(arguments.getString(PACKAGE_NAME)) val userId = arguments.getInt(USER_ID) - val listModel = rememberContext { context -> factory.createModel(permission, context) } + val listModel = appListTemplate.rememberModel(permissionType) TogglePermissionAppInfoPage(listModel, packageName, userId) } diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt index e1354bdd9871..3cc5854b95e4 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListModel.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt @@ -47,20 +47,14 @@ interface TogglePermissionAppListModel<T : AppRecord> { fun setAllowed(record: T, newAllowed: Boolean) } -interface TogglePermissionAppListModelFactory { - fun createModel( - permission: String, - context: Context, - ): TogglePermissionAppListModel<out AppRecord> +interface TogglePermissionAppListProvider { + val permissionType: String - fun createPageProviders(): List<SettingsPageProvider> = listOf( - TogglePermissionAppListPageProvider(this), - TogglePermissionAppInfoPageProvider(this), - ) + fun createModel(context: Context): TogglePermissionAppListModel<out AppRecord> @Composable - fun EntryItem(permissionType: String) { - val listModel = rememberModel(permissionType) + fun EntryItem() { + val listModel = rememberContext(::createModel) Preference( object : PreferenceModel { override val title = stringResource(listModel.pageTitleResId) @@ -68,8 +62,28 @@ interface TogglePermissionAppListModelFactory { } ) } + + /** + * Gets the route to the toggle permission App List page. + * + * Expose route to enable enter from non-SPA pages. + */ + fun getRoute(): String = + TogglePermissionAppListPageProvider.getRoute(permissionType) } -@Composable -internal fun TogglePermissionAppListModelFactory.rememberModel(permission: String) = - rememberContext { context -> createModel(permission, context) } +class TogglePermissionAppListTemplate( + allProviders: List<TogglePermissionAppListProvider>, +) { + private val listModelProviderMap = allProviders.associateBy { it.permissionType } + + fun createPageProviders(): List<SettingsPageProvider> = listOf( + TogglePermissionAppListPageProvider(this), + TogglePermissionAppInfoPageProvider(this), + ) + + @Composable + internal fun rememberModel(permissionType: String) = rememberContext { context -> + listModelProviderMap.getValue(permissionType).createModel(context) + } +} diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt index 6d00d56e6952..f2eb96277b9b 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt @@ -38,7 +38,7 @@ private const val NAME = "TogglePermissionAppList" private const val PERMISSION = "permission" internal class TogglePermissionAppListPageProvider( - private val factory: TogglePermissionAppListModelFactory, + private val appListTemplate: TogglePermissionAppListTemplate, ) : SettingsPageProvider { override val name = NAME @@ -55,7 +55,7 @@ internal class TogglePermissionAppListPageProvider( @Composable private fun TogglePermissionAppList(permissionType: String) { - val listModel = factory.rememberModel(permissionType) + val listModel = appListTemplate.rememberModel(permissionType) val context = LocalContext.current val internalListModel = remember { TogglePermissionInternalAppListModel(context, listModel) @@ -75,8 +75,14 @@ internal class TogglePermissionAppListPageProvider( } companion object { + /** + * Gets the route to this page. + * + * Expose route to enable enter from non-SPA pages. + */ + internal fun getRoute(permissionType: String) = "$NAME/$permissionType" @Composable - internal fun navigator(permissionType: String) = navigator(route = "$NAME/$permissionType") + internal fun navigator(permissionType: String) = navigator(route = getRoute(permissionType)) } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java index 19409865284c..b64dcca63ac9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java @@ -43,8 +43,6 @@ import java.util.List; public class A2dpProfile implements LocalBluetoothProfile { private static final String TAG = "A2dpProfile"; - private static final int SOURCE_CODEC_TYPE_OPUS = 6; // TODO remove in U - private Context mContext; private BluetoothA2dp mService; @@ -333,7 +331,7 @@ public class A2dpProfile implements LocalBluetoothProfile { case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LC3: index = 6; break; - case SOURCE_CODEC_TYPE_OPUS: // TODO update in U + case BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS: index = 7; break; } diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 78dea891bc12..abcd65b5071a 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -85,7 +85,6 @@ <uses-permission android:name="android.permission.CONTROL_VPN" /> <uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/> <uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL"/> - <uses-permission android:name="android.permission.NETWORK_STACK"/> <!-- Physical hardware --> <uses-permission android:name="android.permission.MANAGE_USB" /> <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" /> @@ -152,6 +151,9 @@ <uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" /> <uses-permission android:name="android.permission.GET_RUNTIME_PERMISSIONS" /> + <!-- For auto-grant the access to the Settings' slice preferences, e.g. volume slices. --> + <uses-permission android:name="android.permission.READ_SEARCH_INDEXABLES" /> + <!-- Needed for WallpaperManager.clear in ImageWallpaper.updateWallpaperLocked --> <uses-permission android:name="android.permission.SET_WALLPAPER"/> @@ -956,5 +958,13 @@ </intent-filter> </receiver> + <receiver android:name=".volume.VolumePanelDialogReceiver" + android:exported="true"> + <intent-filter> + <action android:name="android.settings.panel.action.VOLUME" /> + <action android:name="com.android.systemui.action.LAUNCH_VOLUME_PANEL_DIALOG" /> + <action android:name="com.android.systemui.action.DISMISS_VOLUME_PANEL_DIALOG" /> + </intent-filter> + </receiver> </application> </manifest> diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt new file mode 100644 index 000000000000..3ca8dfe4fd38 --- /dev/null +++ b/packages/SystemUI/ktfmt_includes.txt @@ -0,0 +1,870 @@ ++packages/SystemUI +-packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt +-packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt +-packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt +-packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt +-packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt +-packages/SystemUI/checks/src/com/android/internal/systemui/lint/BindServiceViaContextDetector.kt +-packages/SystemUI/checks/src/com/android/internal/systemui/lint/BroadcastSentViaContextDetector.kt +-packages/SystemUI/checks/src/com/android/internal/systemui/lint/GetMainLooperViaContextDetector.kt +-packages/SystemUI/checks/src/com/android/internal/systemui/lint/RegisterReceiverViaContextDetector.kt +-packages/SystemUI/checks/src/com/android/internal/systemui/lint/SoftwareBitmapDetector.kt +-packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt +-packages/SystemUI/checks/tests/com/android/systemui/lint/BindServiceViaContextDetectorTest.kt +-packages/SystemUI/checks/tests/com/android/systemui/lint/BroadcastSentViaContextDetectorTest.kt +-packages/SystemUI/checks/tests/com/android/systemui/lint/GetMainLooperViaContextDetectorTest.kt +-packages/SystemUI/checks/tests/com/android/systemui/lint/RegisterReceiverViaContextDetectorTest.kt +-packages/SystemUI/checks/tests/com/android/systemui/lint/SoftwareBitmapDetectorTest.kt +-packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt +-packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt +-packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt +-packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt +-packages/SystemUI/shared/src/com/android/systemui/flags/FlagListenable.kt +-packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt +-packages/SystemUI/shared/src/com/android/systemui/flags/FlagSerializer.kt +-packages/SystemUI/shared/src/com/android/systemui/flags/FlagSettingsHelper.kt +-packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt +-packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt +-packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt +-packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +-packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt +-packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt +-packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt +-packages/SystemUI/shared/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerManager.kt +-packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt +-packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt +-packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateManagerFoldProvider.kt +-packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt +-packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt +-packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt +-packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt +-packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt +-packages/SystemUI/src/com/android/keyguard/KeyguardBiometricLockoutLogger.kt +-packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt +-packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt +-packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt +-packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherAnchor.kt +-packages/SystemUI/src/com/android/keyguard/clock/ClockPalette.kt +-packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt +-packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt +-packages/SystemUI/src/com/android/systemui/BootCompleteCache.kt +-packages/SystemUI/src/com/android/systemui/BootCompleteCacheImpl.kt +-packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt +-packages/SystemUI/src/com/android/systemui/ChooserSelector.kt +-packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt +-packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt +-packages/SystemUI/src/com/android/systemui/DualToneHandler.kt +-packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt +-packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt +-packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt +-packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt +-packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt +-packages/SystemUI/src/com/android/systemui/assist/AssistLogger.kt +-packages/SystemUI/src/com/android/systemui/assist/AssistantInvocationEvent.kt +-packages/SystemUI/src/com/android/systemui/assist/AssistantSessionEvent.kt +-packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt +-packages/SystemUI/src/com/android/systemui/biometrics/AlternateUdfpsTouchProvider.kt +-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt +-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.kt +-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt +-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt +-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt +-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt +-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt +-packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt +-packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt +-packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt +-packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt +-packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt +-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt +-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt +-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt +-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt +-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt +-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt +-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt +-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt +-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHapticsSimulator.kt +-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt +-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt +-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt +-packages/SystemUI/src/com/android/systemui/biometrics/Utils.kt +-packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt +-packages/SystemUI/src/com/android/systemui/broadcast/ActionReceiver.kt +-packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt +-packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcherStartable.kt +-packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt +-packages/SystemUI/src/com/android/systemui/broadcast/PendingRemovalStore.kt +-packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt +-packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt +-packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt +-packages/SystemUI/src/com/android/systemui/camera/CameraIntents.kt +-packages/SystemUI/src/com/android/systemui/camera/CameraIntentsWrapper.kt +-packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt +-packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt +-packages/SystemUI/src/com/android/systemui/controls/ControlsMetricsLogger.kt +-packages/SystemUI/src/com/android/systemui/controls/ControlsMetricsLoggerImpl.kt +-packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt +-packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt +-packages/SystemUI/src/com/android/systemui/controls/TooltipManager.kt +-packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt +-packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt +-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt +-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt +-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt +-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt +-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt +-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt +-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfiguration.kt +-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImpl.kt +-packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt +-packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt +-packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt +-packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsFeatureEnabled.kt +-packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt +-packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt +-packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt +-packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt +-packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt +-packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt +-packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +-packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt +-packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt +-packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt +-packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt +-packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt +-packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt +-packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt +-packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt +-packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/Behavior.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/ControlWithState.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/CornerDrawable.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt +-packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt +-packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +-packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt +-packages/SystemUI/src/com/android/systemui/decor/DecorProviderFactory.kt +-packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt +-packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt +-packages/SystemUI/src/com/android/systemui/decor/PrivacyDotDecorProviderFactory.kt +-packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderFactory.kt +-packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt +-packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt +-packages/SystemUI/src/com/android/systemui/demomode/DemoModeAvailabilityTracker.kt +-packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt +-packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt +-packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt +-packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt +-packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt +-packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt +-packages/SystemUI/src/com/android/systemui/dump/DumpsysTableLogger.kt +-packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt +-packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt +-packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt +-packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt +-packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt +-packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt +-packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt +-packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt +-packages/SystemUI/src/com/android/systemui/log/LogLevel.kt +-packages/SystemUI/src/com/android/systemui/log/LogMessage.kt +-packages/SystemUI/src/com/android/systemui/log/LogMessageImpl.kt +-packages/SystemUI/src/com/android/systemui/log/LogcatEchoTracker.kt +-packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt +-packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerProd.kt +-packages/SystemUI/src/com/android/systemui/media/AnimationBindHandler.kt +-packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt +-packages/SystemUI/src/com/android/systemui/media/GutsViewHolder.kt +-packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt +-packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt +-packages/SystemUI/src/com/android/systemui/media/LightSourceDrawable.kt +-packages/SystemUI/src/com/android/systemui/media/LocalMediaManagerFactory.kt +-packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +-packages/SystemUI/src/com/android/systemui/media/MediaCarouselControllerLogger.kt +-packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt +-packages/SystemUI/src/com/android/systemui/media/MediaData.kt +-packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt +-packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt +-packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +-packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt +-packages/SystemUI/src/com/android/systemui/media/MediaFeatureFlag.kt +-packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt +-packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt +-packages/SystemUI/src/com/android/systemui/media/MediaHost.kt +-packages/SystemUI/src/com/android/systemui/media/MediaHostStatesManager.kt +-packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt +-packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt +-packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt +-packages/SystemUI/src/com/android/systemui/media/MediaScrollView.kt +-packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt +-packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt +-packages/SystemUI/src/com/android/systemui/media/MediaTimeoutLogger.kt +-packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt +-packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt +-packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt +-packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt +-packages/SystemUI/src/com/android/systemui/media/MetadataAnimationHandler.kt +-packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt +-packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserLogger.kt +-packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt +-packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt +-packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaData.kt +-packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaDataProvider.kt +-packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt +-packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt +-packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt +-packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt +-packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt +-packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionCli.kt +-packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt +-packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerFactory.kt +-packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt +-packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt +-packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesManager.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttFlags.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt +-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLogger.kt +-packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt +-packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt +-packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt +-packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt +-packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt +-packages/SystemUI/src/com/android/systemui/privacy/MediaProjectionPrivacyItemMonitor.kt +-packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt +-packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt +-packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipEvent.kt +-packages/SystemUI/src/com/android/systemui/privacy/PrivacyConfig.kt +-packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt +-packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt +-packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogEvent.kt +-packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt +-packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt +-packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt +-packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt +-packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt +-packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt +-packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt +-packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt +-packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt +-packages/SystemUI/src/com/android/systemui/qs/QSExpansionPathInterpolator.kt +-packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt +-packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt +-packages/SystemUI/src/com/android/systemui/qs/QSUtils.kt +-packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt +-packages/SystemUI/src/com/android/systemui/qs/VisibilityChangedDispatcher.kt +-packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt +-packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.kt +-packages/SystemUI/src/com/android/systemui/qs/external/CustomTileStatePersister.kt +-packages/SystemUI/src/com/android/systemui/qs/external/QSExternalModule.kt +-packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialog.kt +-packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialogEventLogger.kt +-packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt +-packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt +-packages/SystemUI/src/com/android/systemui/qs/tileimpl/HeightOverrideable.kt +-packages/SystemUI/src/com/android/systemui/qs/tileimpl/IgnorableChildLinearLayout.kt +-packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt +-packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt +-packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt +-packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt +-packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt +-packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt +-packages/SystemUI/src/com/android/systemui/ripple/RippleShaderUtilLibrary.kt +-packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt +-packages/SystemUI/src/com/android/systemui/ripple/SdfShaderLibrary.kt +-packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt +-packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt +-packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt +-packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt +-packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt +-packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt +-packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt +-packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt +-packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt +-packages/SystemUI/src/com/android/systemui/settings/UserFileManager.kt +-packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt +-packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt +-packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt +-packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessMirrorHandler.kt +-packages/SystemUI/src/com/android/systemui/settings/brightness/MirroredBrightnessController.kt +-packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManager.kt +-packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt +-packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt +-packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt +-packages/SystemUI/src/com/android/systemui/shade/NotifPanelEvents.kt +-packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt +-packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt +-packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt +-packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt +-packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt +-packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt +-packages/SystemUI/src/com/android/systemui/shade/transition/SplitShadeOverScroller.kt +-packages/SystemUI/src/com/android/systemui/smartspace/SmartspacePrecondition.kt +-packages/SystemUI/src/com/android/systemui/smartspace/SmartspaceTargetFilter.kt +-packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt +-packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt +-packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenAndDreamTargetFilter.kt +-packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt +-packages/SystemUI/src/com/android/systemui/statusbar/AbstractLockscreenShadeTransitionController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarWifiView.kt +-packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt +-packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt +-packages/SystemUI/src/com/android/systemui/statusbar/LockScreenShadeOverScroller.kt +-packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeScrimTransitionController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt +-packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt +-packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt +-packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt +-packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt +-packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt +-packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt +-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityState.kt +-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalControllerFactory.kt +-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileState.kt +-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileStatusTrackerFactory.kt +-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalCallback.kt +-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiState.kt +-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiStatusTrackerFactory.kt +-packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt +-packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartCentralSurfacesModule.kt +-packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt +-packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt +-packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt +-packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt +-packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt +-packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/FeedbackIcon.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImpl.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineDumper.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DebugModeCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManager.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManagerImpl.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifStabilityManager.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTracker.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtender.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DebugModeFilterProvider.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/NotificationVisibilityProviderImpl.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionHeaderVisibilityProvider.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionStyleProvider.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/MediaContainerController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGroupController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewManager.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifRowController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifShadeEventSource.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifStackController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotificationVisibilityProvider.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderExtensions.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractor.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/people/ViewPipeline.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/RemoteInputViewModule.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCallTemplateViewWrapper.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProvider.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocationPublisher.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemBarAttributesListener.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarIconBlocklist.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometer.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallFlags.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoProcessor.kt +-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt +-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt +-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt +-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt +-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt +-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt +-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt +-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyState.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyViewHolder.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/WalletController.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/WalletControllerImpl.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/RemoteInput.kt +-packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/SmartRepliesInflationModule.kt +-packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt +-packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt +-packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt +-packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt +-packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt +-packages/SystemUI/src/com/android/systemui/tv/TVSystemUICoreStartableModule.kt +-packages/SystemUI/src/com/android/systemui/unfold/FoldStateLogger.kt +-packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt +-packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt +-packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt +-packages/SystemUI/src/com/android/systemui/unfold/UnfoldProgressProvider.kt +-packages/SystemUI/src/com/android/systemui/user/UserCreator.kt +-packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt +-packages/SystemUI/src/com/android/systemui/user/UserSwitcherPopupMenu.kt +-packages/SystemUI/src/com/android/systemui/user/UserSwitcherRootView.kt +-packages/SystemUI/src/com/android/systemui/util/AsyncActivityLauncher.kt +-packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt +-packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt +-packages/SystemUI/src/com/android/systemui/util/DelayableMarqueeTextView.kt +-packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt +-packages/SystemUI/src/com/android/systemui/util/InitializationChecker.kt +-packages/SystemUI/src/com/android/systemui/util/LargeScreenUtils.kt +-packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt +-packages/SystemUI/src/com/android/systemui/util/NeverExactlyLinearLayout.kt +-packages/SystemUI/src/com/android/systemui/util/NoRemeasureMotionLayout.kt +-packages/SystemUI/src/com/android/systemui/util/PluralMessageFormater.kt +-packages/SystemUI/src/com/android/systemui/util/RingerModeTracker.kt +-packages/SystemUI/src/com/android/systemui/util/RingerModeTrackerImpl.kt +-packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt +-packages/SystemUI/src/com/android/systemui/util/SafeMarqueeTextView.kt +-packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt +-packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt +-packages/SystemUI/src/com/android/systemui/util/UserAwareController.kt +-packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt +-packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt +-packages/SystemUI/src/com/android/systemui/util/animation/MeasurementInput.kt +-packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt +-packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt +-packages/SystemUI/src/com/android/systemui/util/animation/UniqueObjectHostView.kt +-packages/SystemUI/src/com/android/systemui/util/collection/RingBuffer.kt +-packages/SystemUI/src/com/android/systemui/util/concurrency/Execution.kt +-packages/SystemUI/src/com/android/systemui/util/concurrency/PendingTasksContainer.kt +-packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt +-packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt +-packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt +-packages/SystemUI/src/com/android/systemui/util/kotlin/IpcSerializer.kt +-packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt +-packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt +-packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt +-packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialogReceiver.kt +-packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt +-packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt +-packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt +-packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt +-packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt +-packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt +-packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt +-packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt +-packages/SystemUI/tests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt +-packages/SystemUI/tests/src/com/android/keyguard/clock/ClockPaletteTest.kt +-packages/SystemUI/tests/src/com/android/keyguard/clock/ViewPreviewerTest.kt +-packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt +-packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt +-packages/SystemUI/tests/src/com/android/systemui/InstanceIdSequenceFake.kt +-packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt +-packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt +-packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt +-packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +-packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt +-packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +-packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt +-packages/SystemUI/tests/src/com/android/systemui/broadcast/ActionReceiverTest.kt +-packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt +-packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/broadcast/PendingRemovalStoreTest.kt +-packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt +-packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt +-packages/SystemUI/tests/src/com/android/systemui/camera/CameraIntentsTest.kt +-packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapperTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/management/AppAdapterTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/management/TestControlsRequestDialog.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt +-packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt +-packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt +-packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt +-packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt +-packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt +-packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt +-packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt +-packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/lifecycle/InstantTaskExecutorRule.kt +-packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/AnimationBindHandlerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/MediaSessionBasedFilterTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt +-packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/MetadataAnimationHandlerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/SmartspaceMediaDataTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyChipBuilderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyConfigFlagsTest.kt +-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt +-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/QSContainerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/SettingObserverTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/carrier/CellSignalStateTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileStatePersisterTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/external/TileRequestDialogEventLoggerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/external/TileRequestDialogTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/ResourceIconTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/TilesStatesTextTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt +-packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/ripple/RippleViewTest.kt +-packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordDialogTest.kt +-packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt +-packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shade/transition/SplitShadeOverScrollerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplingInstanceTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt +-packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/DisableFlagsLoggerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandRegistryTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemBarAttributesListenerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLoggerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManagerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FlashlightControllerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt +-packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt +-packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt +-packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt +-packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt +-packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt +-packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt +-packages/SystemUI/tests/src/com/android/systemui/util/FakeSharedPreferencesTest.kt +-packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt +-packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt +-packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt +-packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt +-packages/SystemUI/tests/src/com/android/systemui/util/collection/RingBufferTest.kt +-packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt +-packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt +-packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt +-packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt +-packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt +-packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt +-packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt +-packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/SizeScreenStatusProvider.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldMain.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt +-packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt diff --git a/packages/SystemUI/res/layout/media_ttt_chip.xml b/packages/SystemUI/res/layout/media_ttt_chip.xml index d88680669fe0..ae8e38e2634b 100644 --- a/packages/SystemUI/res/layout/media_ttt_chip.xml +++ b/packages/SystemUI/res/layout/media_ttt_chip.xml @@ -16,7 +16,7 @@ <!-- Wrap in a frame layout so that we can update the margins on the inner layout. (Since this view is the root view of a window, we cannot change the root view's margins.) --> <!-- Alphas start as 0 because the view will be animated in. --> -<FrameLayout +<com.android.systemui.media.taptotransfer.sender.MediaTttChipRootView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:id="@+id/media_ttt_sender_chip" @@ -97,4 +97,4 @@ /> </LinearLayout> -</FrameLayout> +</com.android.systemui.media.taptotransfer.sender.MediaTttChipRootView> diff --git a/packages/SystemUI/res/layout/volume_panel_dialog.xml b/packages/SystemUI/res/layout/volume_panel_dialog.xml new file mode 100644 index 000000000000..99a1b5cc19dd --- /dev/null +++ b/packages/SystemUI/res/layout/volume_panel_dialog.xml @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2022 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. + --> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/volume_panel_dialog" + android:layout_width="@dimen/large_dialog_width" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@style/Widget.SliceView.Panel" + android:gravity="center_vertical|center_horizontal" + android:layout_marginTop="@dimen/dialog_top_padding" + android:layout_marginBottom="@dimen/dialog_bottom_padding" + android:orientation="vertical"> + + <TextView + android:id="@+id/volume_panel_dialog_title" + android:ellipsize="end" + android:gravity="center_vertical|center_horizontal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/sound_settings" + android:textAppearance="@style/TextAppearance.Dialog.Title"/> + </LinearLayout> + + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/volume_panel_parent_layout" + android:scrollbars="vertical" + android:layout_width="match_parent" + android:layout_height="0dp" + android:minHeight="304dp" + android:layout_weight="1" + android:overScrollMode="never"/> + + <LinearLayout + android:id="@+id/button_layout" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginTop="@dimen/dialog_button_vertical_padding" + android:layout_marginStart="@dimen/dialog_side_padding" + android:layout_marginEnd="@dimen/dialog_side_padding" + android:layout_marginBottom="@dimen/dialog_bottom_padding" + android:baselineAligned="false" + android:clickable="false" + android:focusable="false"> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_gravity="start|center_vertical" + android:orientation="vertical"> + <Button + android:id="@+id/settings_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/volume_panel_dialog_settings_button" + android:ellipsize="end" + android:maxLines="1" + style="@style/Widget.Dialog.Button.BorderButton" + android:clickable="true" + android:focusable="true"/> + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/dialog_button_horizontal_padding" + android:layout_gravity="end|center_vertical"> + <Button + android:id="@+id/done_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/inline_done_button" + style="@style/Widget.Dialog.Button" + android:maxLines="1" + android:ellipsize="end" + android:clickable="true" + android:focusable="true"/> + </LinearLayout> + </LinearLayout> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/volume_panel_slice_slider_row.xml b/packages/SystemUI/res/layout/volume_panel_slice_slider_row.xml new file mode 100644 index 000000000000..d1303ed88964 --- /dev/null +++ b/packages/SystemUI/res/layout/volume_panel_slice_slider_row.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2022 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. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/slice_slider_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <androidx.slice.widget.SliceView + android:id="@+id/slice_view" + style="@style/Widget.SliceView.Panel.Slider" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingVertical="@dimen/volume_panel_slice_vertical_padding" + android:paddingHorizontal="@dimen/volume_panel_slice_horizontal_padding"/> +</LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index e34d422b6dbc..a19145ddba6b 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -479,6 +479,10 @@ <dimen name="volume_tool_tip_arrow_corner_radius">2dp</dimen> + <!-- Volume panel slices dimensions --> + <dimen name="volume_panel_slice_vertical_padding">8dp</dimen> + <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen> + <!-- Size of each item in the ringer selector drawer. --> <dimen name="volume_ringer_drawer_item_size">42dp</dimen> <dimen name="volume_ringer_drawer_item_size_half">21dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index bfdb17041ad7..c7b2ff34c55f 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1139,6 +1139,11 @@ <!-- Content description for accessibility: Hint if click will disable. [CHAR LIMIT=NONE] --> <string name="volume_odi_captions_hint_disable">disable</string> + <!-- Sound and vibration settings dialog title. [CHAR LIMIT=30] --> + <string name="sound_settings">Sound & vibration</string> + <!-- Label for button to go to sound settings screen [CHAR_LIMIT=30] --> + <string name="volume_panel_dialog_settings_button">Settings</string> + <!-- content description for audio output chooser [CHAR LIMIT=NONE]--> <!-- Screen pinning dialog title. --> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index f7acf06350c6..6d1bcbbb8c99 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -935,6 +935,10 @@ <item name="rowStyle">@style/SliceRow</item> </style> + <style name="Widget.SliceView.Panel.Slider"> + <item name="rowStyle">@style/SliceRow.Slider</item> + </style> + <style name="SliceRow"> <!-- 2dp start padding for the start icon --> <item name="titleItemStartPadding">2dp</item> @@ -956,6 +960,26 @@ <item name="actionDividerHeight">32dp</item> </style> + <style name="SliceRow.Slider"> + <!-- Padding between content and the start icon is 5dp --> + <item name="contentStartPadding">5dp</item> + <item name="contentEndPadding">0dp</item> + + <!-- 0dp start padding for the end item --> + <item name="endItemStartPadding">0dp</item> + <!-- 8dp end padding for the end item --> + <item name="endItemEndPadding">8dp</item> + + <item name="titleSize">20sp</item> + <!-- Align text with slider --> + <item name="titleStartPadding">11dp</item> + <item name="subContentStartPadding">11dp</item> + + <!-- Padding for indeterminate progress bar --> + <item name="progressBarStartPadding">12dp</item> + <item name="progressBarEndPadding">16dp</item> + </style> + <style name="TextAppearance.Dialog.Title" parent="@android:style/TextAppearance.DeviceDefault.Large"> <item name="android:textColor">?android:attr/textColorPrimary</item> <item name="android:textSize">24sp</item> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index e1957c09fef5..93175e19a287 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -418,6 +418,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED, state); getCurrentSecurityController().onResume(reason); + updateSideFpsVisibility(); } mView.onResume( mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()), diff --git a/packages/SystemUI/src/com/android/systemui/ChooserSelector.kt b/packages/SystemUI/src/com/android/systemui/ChooserSelector.kt new file mode 100644 index 000000000000..109be40ce10f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/ChooserSelector.kt @@ -0,0 +1,67 @@ +package com.android.systemui + +import android.content.ComponentName +import android.content.Context +import android.content.pm.PackageManager +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.FlagListenable +import com.android.systemui.flags.Flags +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withContext + +@SysUISingleton +class ChooserSelector @Inject constructor( + context: Context, + private val featureFlags: FeatureFlags, + @Application private val coroutineScope: CoroutineScope, + @Background private val bgDispatcher: CoroutineDispatcher +) : CoreStartable(context) { + + private val packageManager = context.packageManager + private val chooserComponent = ComponentName.unflattenFromString( + context.resources.getString(ChooserSelectorResourceHelper.CONFIG_CHOOSER_ACTIVITY)) + + override fun start() { + coroutineScope.launch { + val listener = FlagListenable.Listener { event -> + if (event.flagId == Flags.CHOOSER_UNBUNDLED.id) { + launch { updateUnbundledChooserEnabled() } + event.requestNoRestart() + } + } + featureFlags.addListener(Flags.CHOOSER_UNBUNDLED, listener) + updateUnbundledChooserEnabled() + + awaitCancellationAndThen { featureFlags.removeListener(listener) } + } + } + + private suspend fun updateUnbundledChooserEnabled() { + setUnbundledChooserEnabled(withContext(bgDispatcher) { + featureFlags.isEnabled(Flags.CHOOSER_UNBUNDLED) + }) + } + + private fun setUnbundledChooserEnabled(enabled: Boolean) { + val newState = if (enabled) { + PackageManager.COMPONENT_ENABLED_STATE_ENABLED + } else { + PackageManager.COMPONENT_ENABLED_STATE_DISABLED + } + packageManager.setComponentEnabledSetting(chooserComponent, newState, /* flags = */ 0) + } + + suspend inline fun awaitCancellation(): Nothing = suspendCancellableCoroutine { } + suspend inline fun awaitCancellationAndThen(block: () -> Unit): Nothing = try { + awaitCancellation() + } finally { + block() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/ChooserSelectorResourceHelper.java b/packages/SystemUI/src/com/android/systemui/ChooserSelectorResourceHelper.java new file mode 100644 index 000000000000..7a2de7b6a78d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/ChooserSelectorResourceHelper.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 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; + +import androidx.annotation.StringRes; + +import com.android.internal.R; + +/** Helper class for referencing resources */ +class ChooserSelectorResourceHelper { + + private ChooserSelectorResourceHelper() { + } + + @StringRes + static final int CONFIG_CHOOSER_ACTIVITY = R.string.config_chooserActivity; +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java index 8ba6f1c4a411..d60a22204b3d 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java @@ -26,6 +26,7 @@ import com.android.systemui.people.widget.PeopleSpaceWidgetProvider; import com.android.systemui.screenshot.ActionProxyReceiver; import com.android.systemui.screenshot.DeleteScreenshotReceiver; import com.android.systemui.screenshot.SmartActionsReceiver; +import com.android.systemui.volume.VolumePanelDialogReceiver; import dagger.Binds; import dagger.Module; @@ -78,6 +79,15 @@ public abstract class DefaultBroadcastReceiverBinder { */ @Binds @IntoMap + @ClassKey(VolumePanelDialogReceiver.class) + public abstract BroadcastReceiver bindVolumePanelDialogReceiver( + VolumePanelDialogReceiver broadcastReceiver); + + /** + * + */ + @Binds + @IntoMap @ClassKey(PeopleSpaceWidgetPinnedReceiver.class) public abstract BroadcastReceiver bindPeopleSpaceWidgetPinnedReceiver( PeopleSpaceWidgetPinnedReceiver broadcastReceiver); diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt index 6db3e82a77b0..8bb27a7bc217 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt @@ -17,6 +17,7 @@ package com.android.systemui.dagger import com.android.keyguard.KeyguardBiometricLockoutLogger +import com.android.systemui.ChooserSelector import com.android.systemui.CoreStartable import com.android.systemui.LatencyTester import com.android.systemui.ScreenDecorations @@ -60,6 +61,12 @@ abstract class SystemUICoreStartableModule { @ClassKey(AuthController::class) abstract fun bindAuthController(service: AuthController): CoreStartable + /** Inject into ChooserCoreStartable. */ + @Binds + @IntoMap + @ClassKey(ChooserSelector::class) + abstract fun bindChooserSelector(sysui: ChooserSelector): CoreStartable + /** Inject into ClipboardListener. */ @Binds @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java index 567bdbc01170..a981f255a873 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java @@ -70,11 +70,7 @@ public class SmartSpaceComplication implements Complication { new BcSmartspaceDataPlugin.SmartspaceTargetListener() { @Override public void onSmartspaceTargetsUpdated(List<? extends Parcelable> targets) { - if (!targets.isEmpty()) { - mDreamOverlayStateController.addComplication(mComplication); - } else { - mDreamOverlayStateController.removeComplication(mComplication); - } + mDreamOverlayStateController.addComplication(mComplication); } }; diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index 45237a358700..c4553c4cb299 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -252,6 +252,9 @@ public class Flags { // 1400 - columbus, b/242800729 public static final UnreleasedFlag QUICK_TAP_IN_PCC = new UnreleasedFlag(1400); + // 1500 - chooser + public static final UnreleasedFlag CHOOSER_UNBUNDLED = new UnreleasedFlag(1500); + // Pay no attention to the reflection behind the curtain. // ========================== Curtain ========================== // | | diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java index 9e2b7c748631..a3dc77993d30 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java +++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java @@ -50,7 +50,6 @@ import com.android.settingslib.bluetooth.LocalBluetoothAdapter; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import com.android.systemui.CoreStartable; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; @@ -61,6 +60,7 @@ import java.util.List; import java.util.Set; import javax.inject.Inject; +import javax.inject.Provider; /** */ @SysUISingleton @@ -106,6 +106,8 @@ public class KeyboardUI extends CoreStartable implements InputManager.OnTabletMo protected volatile Context mContext; + private final Provider<LocalBluetoothManager> mBluetoothManagerProvider; + private boolean mEnabled; private String mKeyboardName; private CachedBluetoothDeviceManager mCachedDeviceManager; @@ -122,8 +124,9 @@ public class KeyboardUI extends CoreStartable implements InputManager.OnTabletMo private int mState; @Inject - public KeyboardUI(Context context) { + public KeyboardUI(Context context, Provider<LocalBluetoothManager> bluetoothManagerProvider) { super(context); + this.mBluetoothManagerProvider = bluetoothManagerProvider; } @Override @@ -181,7 +184,7 @@ public class KeyboardUI extends CoreStartable implements InputManager.OnTabletMo return; } - LocalBluetoothManager bluetoothManager = Dependency.get(LocalBluetoothManager.class); + LocalBluetoothManager bluetoothManager = mBluetoothManagerProvider.get(); if (bluetoothManager == null) { if (DEBUG) { Slog.e(TAG, "Failed to retrieve LocalBluetoothManager instance"); diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 012d76651b23..b02393b4f73a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -488,8 +488,8 @@ public class MediaControlPanel { TextView deviceName = mMediaViewHolder.getSeamlessText(); final MediaDeviceData device = data.getDevice(); - final boolean enabled; - final boolean seamlessDisabled; + final boolean isTapEnabled; + final boolean useDisabledAlpha; final int iconResource; CharSequence deviceString; if (showBroadcastButton) { @@ -499,21 +499,25 @@ public class MediaControlPanel { && TextUtils.equals(device.getName(), MediaDataUtils.getAppLabel(mContext, mPackageName, mContext.getString( R.string.bt_le_audio_broadcast_dialog_unknown_name))); - seamlessDisabled = !mIsCurrentBroadcastedApp; + useDisabledAlpha = !mIsCurrentBroadcastedApp; // Always be enabled if the broadcast button is shown - enabled = true; + isTapEnabled = true; + + // Defaults for broadcasting state deviceString = mContext.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name); iconResource = R.drawable.settings_input_antenna; } else { // Disable clicking on output switcher for invalid devices and resumption controls - seamlessDisabled = (device != null && !device.getEnabled()) || data.getResumption(); - enabled = !seamlessDisabled; + useDisabledAlpha = (device != null && !device.getEnabled()) || data.getResumption(); + isTapEnabled = !useDisabledAlpha; + + // Defaults for non-broadcasting state deviceString = mContext.getString(R.string.media_seamless_other_device); iconResource = R.drawable.ic_media_home_devices; } - mMediaViewHolder.getSeamlessButton().setAlpha(seamlessDisabled ? DISABLED_ALPHA : 1.0f); - seamlessView.setEnabled(enabled); + mMediaViewHolder.getSeamlessButton().setAlpha(useDisabledAlpha ? DISABLED_ALPHA : 1.0f); + seamlessView.setEnabled(isTapEnabled); if (device != null) { Drawable icon = device.getIcon(); @@ -524,7 +528,9 @@ public class MediaControlPanel { } else { iconView.setImageDrawable(icon); } - deviceString = device.getName(); + if (device.getName() != null) { + deviceString = device.getName(); + } } else { // Set to default icon iconView.setImageResource(iconResource); diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 7b497ade683c..c48271e0348a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -518,9 +518,20 @@ class MediaDataManager( } val actions = createActionsFromState(it.packageName, mediaControllerFactory.create(it.token), UserHandle(it.userId)) - val data = it.copy( - semanticActions = actions, - isPlaying = isPlayingState(state.state)) + + // Control buttons + // If flag is enabled and controller has a PlaybackState, + // create actions from session info + // otherwise, no need to update semantic actions. + val data = if (actions != null) { + it.copy( + semanticActions = actions, + isPlaying = isPlayingState(state.state)) + } else { + it.copy( + isPlaying = isPlayingState(state.state) + ) + } if (DEBUG) Log.d(TAG, "State updated outside of notification") onMediaDataLoaded(key, key, data) } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt index 25186597e0e1..b3a4ddf8ec1f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt @@ -348,7 +348,11 @@ class MediaDeviceManager @Inject constructor( // If we have a controller but get a null route, then don't trust the device val enabled = device != null && (controller == null || route != null) - val name = route?.name?.toString() ?: device?.name + val name = if (controller == null || route != null) { + route?.name?.toString() ?: device?.name + } else { + null + } current = MediaDeviceData(enabled, device?.iconWithoutBackground, name, id = device?.id, showBroadcastButton = false) } diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt index a153cb6c0d31..f93c671f6740 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt @@ -26,6 +26,7 @@ import com.android.internal.logging.UiEventLogger import com.android.internal.statusbar.IUndoMediaTransferCallback import com.android.systemui.R import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS +import com.android.systemui.plugins.FalsingManager /** * A class enumerating all the possible states of the media tap-to-transfer chip on the sender @@ -106,12 +107,15 @@ enum class ChipStateSender( controllerSender: MediaTttChipControllerSender, routeInfo: MediaRoute2Info, undoCallback: IUndoMediaTransferCallback?, - uiEventLogger: MediaTttSenderUiEventLogger + uiEventLogger: MediaTttSenderUiEventLogger, + falsingManager: FalsingManager, ): View.OnClickListener? { if (undoCallback == null) { return null } return View.OnClickListener { + if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return@OnClickListener + uiEventLogger.logUndoClicked( MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_RECEIVER_CLICKED ) @@ -141,12 +145,15 @@ enum class ChipStateSender( controllerSender: MediaTttChipControllerSender, routeInfo: MediaRoute2Info, undoCallback: IUndoMediaTransferCallback?, - uiEventLogger: MediaTttSenderUiEventLogger + uiEventLogger: MediaTttSenderUiEventLogger, + falsingManager: FalsingManager, ): View.OnClickListener? { if (undoCallback == null) { return null } return View.OnClickListener { + if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return@OnClickListener + uiEventLogger.logUndoClicked( MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED ) @@ -212,7 +219,8 @@ enum class ChipStateSender( controllerSender: MediaTttChipControllerSender, routeInfo: MediaRoute2Info, undoCallback: IUndoMediaTransferCallback?, - uiEventLogger: MediaTttSenderUiEventLogger + uiEventLogger: MediaTttSenderUiEventLogger, + falsingManager: FalsingManager, ): View.OnClickListener? = null companion object { diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt index 933548963390..5ad82fd9fd8f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt @@ -22,21 +22,25 @@ import android.media.MediaRoute2Info import android.os.PowerManager import android.util.Log import android.view.Gravity +import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.view.WindowManager import android.view.accessibility.AccessibilityManager import android.widget.TextView import com.android.internal.statusbar.IUndoMediaTransferCallback +import com.android.systemui.Gefingerpoken import com.android.systemui.R import com.android.systemui.animation.Interpolators import com.android.systemui.animation.ViewHierarchyAnimator +import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.media.taptotransfer.common.ChipInfoCommon import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon import com.android.systemui.media.taptotransfer.common.MediaTttLogger import com.android.systemui.media.taptotransfer.common.MediaTttRemovalReason +import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.concurrency.DelayableExecutor @@ -58,7 +62,9 @@ class MediaTttChipControllerSender @Inject constructor( accessibilityManager: AccessibilityManager, configurationController: ConfigurationController, powerManager: PowerManager, - private val uiEventLogger: MediaTttSenderUiEventLogger + private val uiEventLogger: MediaTttSenderUiEventLogger, + private val falsingManager: FalsingManager, + private val falsingCollector: FalsingCollector, ) : MediaTttChipControllerCommon<ChipSenderInfo>( context, logger, @@ -70,6 +76,9 @@ class MediaTttChipControllerSender @Inject constructor( powerManager, R.layout.media_ttt_chip, ) { + + private lateinit var parent: MediaTttChipRootView + override val windowLayoutParams = commonWindowLayoutParams.apply { gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL) } @@ -121,6 +130,15 @@ class MediaTttChipControllerSender @Inject constructor( val chipState = newChipInfo.state + // Detect falsing touches on the chip. + parent = currentChipView as MediaTttChipRootView + parent.touchHandler = object : Gefingerpoken { + override fun onTouchEvent(ev: MotionEvent?): Boolean { + falsingCollector.onTouchEvent(ev) + return false + } + } + // App icon val iconName = setIcon(currentChipView, newChipInfo.routeInfo.clientPackageName) @@ -136,7 +154,11 @@ class MediaTttChipControllerSender @Inject constructor( // Undo val undoView = currentChipView.requireViewById<View>(R.id.undo) val undoClickListener = chipState.undoClickListener( - this, newChipInfo.routeInfo, newChipInfo.undoCallback, uiEventLogger + this, + newChipInfo.routeInfo, + newChipInfo.undoCallback, + uiEventLogger, + falsingManager, ) undoView.setOnClickListener(undoClickListener) undoView.visibility = (undoClickListener != null).visibleIfTrue() diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipRootView.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipRootView.kt new file mode 100644 index 000000000000..3373159fba4e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipRootView.kt @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 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.media.taptotransfer.sender + +import android.content.Context +import android.util.AttributeSet +import android.view.MotionEvent +import android.widget.FrameLayout +import com.android.systemui.Gefingerpoken + +/** A simple subclass that allows for observing touch events on chip. */ +class MediaTttChipRootView( + context: Context, + attrs: AttributeSet? +) : FrameLayout(context, attrs) { + + /** Assign this field to observe touch events. */ + var touchHandler: Gefingerpoken? = null + + override fun dispatchTouchEvent(ev: MotionEvent): Boolean { + touchHandler?.onTouchEvent(ev) + return super.dispatchTouchEvent(ev) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java index 3f931088ec83..5da480968b89 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java @@ -17,7 +17,14 @@ import java.util.Set; import javax.inject.Inject; -/** */ +/** + * Plays a animation to reveal newly added QS tiles. + * + * The aniumation is played when the user fully opens Quick Settings, and is only shown for + * <li> tiles added automatically (not through user customization) + * <li> tiles not have been revealed before (memoized via {@code QS_TILE_SPECS_REVEALED} + * preference) + */ public class QSTileRevealController { private static final long QS_REVEAL_TILES_DELAY = 500L; @@ -39,6 +46,7 @@ public class QSTileRevealController { }); } }; + QSTileRevealController(Context context, QSPanelController qsPanelController, PagedTileLayout pagedTileLayout, QSCustomizerController qsCustomizerController) { mContext = context; diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt index a918e5d9e106..309059fdb9ad 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt @@ -17,6 +17,7 @@ package com.android.systemui.screenshot import android.graphics.Insets +import android.util.Log import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler import com.android.internal.util.ScreenshotHelper.ScreenshotRequest @@ -61,8 +62,9 @@ class RequestProcessor @Inject constructor( ) { val info = policy.findPrimaryContent(policy.getDefaultDisplayId()) + Log.d(TAG, "findPrimaryContent: $info") - result = if (policy.isManagedProfile(info.userId)) { + result = if (policy.isManagedProfile(info.user.identifier)) { val image = capture.captureTask(info.taskId) ?: error("Task snapshot returned a null Bitmap!") @@ -70,7 +72,7 @@ class RequestProcessor @Inject constructor( ScreenshotRequest( TAKE_SCREENSHOT_PROVIDED_IMAGE, request.source, HardwareBitmapBundler.hardwareBitmapToBundle(image), - info.bounds, Insets.NONE, info.taskId, info.userId, info.component + info.bounds, Insets.NONE, info.taskId, info.user.identifier, info.component ) } else { // Create a new request of the same type which includes the top component diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt index 3580010cc1e8..f73d2041af95 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt @@ -19,6 +19,7 @@ package com.android.systemui.screenshot import android.annotation.UserIdInt import android.content.ComponentName import android.graphics.Rect +import android.os.UserHandle import android.view.Display /** @@ -42,7 +43,7 @@ interface ScreenshotPolicy { data class DisplayContentInfo( val component: ComponentName, val bounds: Rect, - @UserIdInt val userId: Int, + val user: UserHandle, val taskId: Int, ) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt index ba809f676f1e..c2a50609b6a5 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt @@ -29,9 +29,11 @@ import android.content.Intent import android.graphics.Rect import android.os.Process import android.os.RemoteException +import android.os.UserHandle import android.os.UserManager import android.util.Log import android.view.Display.DEFAULT_DISPLAY +import com.android.internal.annotations.VisibleForTesting import com.android.internal.infra.ServiceConnector import com.android.systemui.SystemUIService import com.android.systemui.dagger.SysUISingleton @@ -45,21 +47,13 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext @SysUISingleton -internal class ScreenshotPolicyImpl @Inject constructor( +internal open class ScreenshotPolicyImpl @Inject constructor( context: Context, private val userMgr: UserManager, private val atmService: IActivityTaskManager, @Background val bgDispatcher: CoroutineDispatcher, ) : ScreenshotPolicy { - private val systemUiContent = - DisplayContentInfo( - ComponentName(context, SystemUIService::class.java), - Rect(), - ActivityTaskManager.INVALID_TASK_ID, - Process.myUserHandle().identifier, - ) - private val proxyConnector: ServiceConnector<IScreenshotProxy> = ServiceConnector.Impl( context, @@ -78,6 +72,9 @@ internal class ScreenshotPolicyImpl @Inject constructor( } private fun nonPipVisibleTask(info: RootTaskInfo): Boolean { + if (DEBUG) { + debugLogRootTaskInfo(info) + } return info.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED && info.isVisible && info.isRunning && @@ -99,58 +96,46 @@ internal class ScreenshotPolicyImpl @Inject constructor( } val taskInfoList = getAllRootTaskInfosOnDisplay(displayId) - if (DEBUG) { - debugLogRootTaskInfos(taskInfoList) - } // If no visible task is located, then report SystemUI as the foreground content val target = taskInfoList.firstOrNull(::nonPipVisibleTask) ?: return systemUiContent - - val topActivity: ComponentName = target.topActivity ?: error("should not be null") - val topChildTask = target.childTaskIds.size - 1 - val childTaskId = target.childTaskIds[topChildTask] - val childTaskUserId = target.childTaskUserIds[topChildTask] - val childTaskBounds = target.childTaskBounds[topChildTask] - - return DisplayContentInfo(topActivity, childTaskBounds, childTaskId, childTaskUserId) + return target.toDisplayContentInfo() } - private fun debugLogRootTaskInfos(taskInfoList: List<RootTaskInfo>) { - for (info in taskInfoList) { - Log.d( - TAG, - "[root task info] " + - "taskId=${info.taskId} " + - "parentTaskId=${info.parentTaskId} " + - "position=${info.position} " + - "positionInParent=${info.positionInParent} " + - "isVisible=${info.isVisible()} " + - "visible=${info.visible} " + - "isFocused=${info.isFocused} " + - "isSleeping=${info.isSleeping} " + - "isRunning=${info.isRunning} " + - "windowMode=${windowingModeToString(info.windowingMode)} " + - "activityType=${activityTypeToString(info.activityType)} " + - "topActivity=${info.topActivity} " + - "topActivityInfo=${info.topActivityInfo} " + - "numActivities=${info.numActivities} " + - "childTaskIds=${Arrays.toString(info.childTaskIds)} " + - "childUserIds=${Arrays.toString(info.childTaskUserIds)} " + - "childTaskBounds=${Arrays.toString(info.childTaskBounds)} " + - "childTaskNames=${Arrays.toString(info.childTaskNames)}" - ) - - for (j in 0 until info.childTaskIds.size) { - Log.d(TAG, " *** [$j] ******") - Log.d(TAG, " *** childTaskIds[$j]: ${info.childTaskIds[j]}") - Log.d(TAG, " *** childTaskUserIds[$j]: ${info.childTaskUserIds[j]}") - Log.d(TAG, " *** childTaskBounds[$j]: ${info.childTaskBounds[j]}") - Log.d(TAG, " *** childTaskNames[$j]: ${info.childTaskNames[j]}") - } + private fun debugLogRootTaskInfo(info: RootTaskInfo) { + Log.d(TAG, "RootTaskInfo={" + + "taskId=${info.taskId} " + + "parentTaskId=${info.parentTaskId} " + + "position=${info.position} " + + "positionInParent=${info.positionInParent} " + + "isVisible=${info.isVisible()} " + + "visible=${info.visible} " + + "isFocused=${info.isFocused} " + + "isSleeping=${info.isSleeping} " + + "isRunning=${info.isRunning} " + + "windowMode=${windowingModeToString(info.windowingMode)} " + + "activityType=${activityTypeToString(info.activityType)} " + + "topActivity=${info.topActivity} " + + "topActivityInfo=${info.topActivityInfo} " + + "numActivities=${info.numActivities} " + + "childTaskIds=${Arrays.toString(info.childTaskIds)} " + + "childUserIds=${Arrays.toString(info.childTaskUserIds)} " + + "childTaskBounds=${Arrays.toString(info.childTaskBounds)} " + + "childTaskNames=${Arrays.toString(info.childTaskNames)}" + + "}" + ) + + for (j in 0 until info.childTaskIds.size) { + Log.d(TAG, " *** [$j] ******") + Log.d(TAG, " *** childTaskIds[$j]: ${info.childTaskIds[j]}") + Log.d(TAG, " *** childTaskUserIds[$j]: ${info.childTaskUserIds[j]}") + Log.d(TAG, " *** childTaskBounds[$j]: ${info.childTaskBounds[j]}") + Log.d(TAG, " *** childTaskNames[$j]: ${info.childTaskNames[j]}") } } - private suspend fun getAllRootTaskInfosOnDisplay(displayId: Int): List<RootTaskInfo> = + @VisibleForTesting + open suspend fun getAllRootTaskInfosOnDisplay(displayId: Int): List<RootTaskInfo> = withContext(bgDispatcher) { try { atmService.getAllRootTaskInfosOnDisplay(displayId) @@ -160,7 +145,8 @@ internal class ScreenshotPolicyImpl @Inject constructor( } } - private suspend fun isNotificationShadeExpanded(): Boolean = suspendCoroutine { k -> + @VisibleForTesting + open suspend fun isNotificationShadeExpanded(): Boolean = suspendCoroutine { k -> proxyConnector .postForResult { it.isNotificationShadeExpanded } .whenComplete { expanded, error -> @@ -171,8 +157,30 @@ internal class ScreenshotPolicyImpl @Inject constructor( } } - companion object { - const val TAG: String = "ScreenshotPolicyImpl" - const val DEBUG: Boolean = false - } + @VisibleForTesting + internal val systemUiContent = + DisplayContentInfo( + ComponentName(context, SystemUIService::class.java), + Rect(), + Process.myUserHandle(), + ActivityTaskManager.INVALID_TASK_ID + ) +} + +private const val TAG: String = "ScreenshotPolicyImpl" +private const val DEBUG: Boolean = false + +@VisibleForTesting +internal fun RootTaskInfo.toDisplayContentInfo(): DisplayContentInfo { + val topActivity: ComponentName = topActivity ?: error("should not be null") + val topChildTask = childTaskIds.size - 1 + val childTaskId = childTaskIds[topChildTask] + val childTaskUserId = childTaskUserIds[topChildTask] + val childTaskBounds = childTaskBounds[topChildTask] + + return DisplayContentInfo( + topActivity, + childTaskBounds, + UserHandle.of(childTaskUserId), + childTaskId) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt index 2ca1bebfcf9f..7b49ecdcd981 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt @@ -1,7 +1,6 @@ package com.android.systemui.statusbar import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.notification.NotificationEntryManager import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener import javax.inject.Inject @@ -12,14 +11,12 @@ import javax.inject.Inject */ @SysUISingleton class NotificationInteractionTracker @Inject constructor( - private val clicker: NotificationClickNotifier, - private val entryManager: NotificationEntryManager + clicker: NotificationClickNotifier, ) : NotifCollectionListener, NotificationInteractionListener { private val interactions = mutableMapOf<String, Boolean>() init { clicker.addNotificationInteractionListener(this) - entryManager.addCollectionListener(this) } fun hasUserInteractedWith(key: String): Boolean { @@ -38,5 +35,3 @@ class NotificationInteractionTracker @Inject constructor( interactions[key] = true } } - -private const val TAG = "NotificationInteractionTracker" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java index 8cb18a06057e..59022c0ffbf2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java @@ -50,7 +50,6 @@ import android.util.Pair; import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.systemui.CoreStartable; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.UiBackground; @@ -76,20 +75,22 @@ public class InstantAppNotifier extends CoreStartable private final Executor mUiBgExecutor; private final ArraySet<Pair<String, Integer>> mCurrentNotifs = new ArraySet<>(); private final CommandQueue mCommandQueue; - private KeyguardStateController mKeyguardStateController; + private final KeyguardStateController mKeyguardStateController; @Inject - public InstantAppNotifier(Context context, CommandQueue commandQueue, - @UiBackground Executor uiBgExecutor) { + public InstantAppNotifier( + Context context, + CommandQueue commandQueue, + @UiBackground Executor uiBgExecutor, + KeyguardStateController keyguardStateController) { super(context); mCommandQueue = commandQueue; mUiBgExecutor = uiBgExecutor; + mKeyguardStateController = keyguardStateController; } @Override public void start() { - mKeyguardStateController = Dependency.get(KeyguardStateController.class); - // listen for user / profile change. try { ActivityManager.getService().registerUserSwitchObserver(mUserSwitchListener, TAG); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt index dbf4810b4fd7..126a986ee5f4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt @@ -18,10 +18,8 @@ package com.android.systemui.statusbar.notification import android.animation.ObjectAnimator import android.util.FloatProperty -import com.android.systemui.Dumpable import com.android.systemui.animation.Interpolators import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.notification.collection.NotificationEntry @@ -34,20 +32,17 @@ import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener -import java.io.PrintWriter import javax.inject.Inject import kotlin.math.min @SysUISingleton class NotificationWakeUpCoordinator @Inject constructor( - dumpManager: DumpManager, private val mHeadsUpManager: HeadsUpManager, private val statusBarStateController: StatusBarStateController, private val bypassController: KeyguardBypassController, private val dozeParameters: DozeParameters, private val screenOffAnimationController: ScreenOffAnimationController -) : OnHeadsUpChangedListener, StatusBarStateController.StateListener, PanelExpansionListener, - Dumpable { +) : OnHeadsUpChangedListener, StatusBarStateController.StateListener, PanelExpansionListener { private val mNotificationVisibility = object : FloatProperty<NotificationWakeUpCoordinator>( "notificationVisibility") { @@ -65,7 +60,6 @@ class NotificationWakeUpCoordinator @Inject constructor( private var mLinearDozeAmount: Float = 0.0f private var mDozeAmount: Float = 0.0f - private var mDozeAmountSource: String = "init" private var mNotificationVisibleAmount = 0.0f private var mNotificationsVisible = false private var mNotificationsVisibleForExpansion = false @@ -148,7 +142,6 @@ class NotificationWakeUpCoordinator @Inject constructor( } init { - dumpManager.registerDumpable(this) mHeadsUpManager.addListener(this) statusBarStateController.addCallback(this) addListener(object : WakeUpListener { @@ -255,14 +248,13 @@ class NotificationWakeUpCoordinator @Inject constructor( // Let's notify the scroller that an animation started notifyAnimationStart(mLinearDozeAmount == 1.0f) } - setDozeAmount(linear, eased, source = "StatusBar") + setDozeAmount(linear, eased) } - fun setDozeAmount(linear: Float, eased: Float, source: String) { + fun setDozeAmount(linear: Float, eased: Float) { val changed = linear != mLinearDozeAmount mLinearDozeAmount = linear mDozeAmount = eased - mDozeAmountSource = source mStackScrollerController.setDozeAmount(mDozeAmount) updateHideAmount() if (changed && linear == 0.0f) { @@ -279,7 +271,7 @@ class NotificationWakeUpCoordinator @Inject constructor( // undefined state, so it's an indication that we should do state cleanup. We override // the doze amount to 0f (not dozing) so that the notifications are no longer hidden. // See: UnlockedScreenOffAnimationController.onFinishedWakingUp() - setDozeAmount(0f, 0f, source = "Override: Shade->Shade (lock cancelled by unlock)") + setDozeAmount(0f, 0f) } if (overrideDozeAmountIfAnimatingScreenOff(mLinearDozeAmount)) { @@ -319,11 +311,12 @@ class NotificationWakeUpCoordinator @Inject constructor( */ private fun overrideDozeAmountIfBypass(): Boolean { if (bypassController.bypassEnabled) { - if (statusBarStateController.state == StatusBarState.KEYGUARD) { - setDozeAmount(1f, 1f, source = "Override: bypass (keyguard)") - } else { - setDozeAmount(0f, 0f, source = "Override: bypass (shade)") + var amount = 1.0f + if (statusBarStateController.state == StatusBarState.SHADE || + statusBarStateController.state == StatusBarState.SHADE_LOCKED) { + amount = 0.0f } + setDozeAmount(amount, amount) return true } return false @@ -339,7 +332,7 @@ class NotificationWakeUpCoordinator @Inject constructor( */ private fun overrideDozeAmountIfAnimatingScreenOff(linearDozeAmount: Float): Boolean { if (screenOffAnimationController.overrideNotificationsFullyDozingOnKeyguard()) { - setDozeAmount(1f, 1f, source = "Override: animating screen off") + setDozeAmount(1f, 1f) return true } @@ -433,24 +426,4 @@ class NotificationWakeUpCoordinator @Inject constructor( */ @JvmDefault fun onPulseExpansionChanged(expandingChanged: Boolean) {} } - - override fun dump(pw: PrintWriter, args: Array<out String>) { - pw.println("mLinearDozeAmount: $mLinearDozeAmount") - pw.println("mDozeAmount: $mDozeAmount") - pw.println("mDozeAmountSource: $mDozeAmountSource") - pw.println("mNotificationVisibleAmount: $mNotificationVisibleAmount") - pw.println("mNotificationsVisible: $mNotificationsVisible") - pw.println("mNotificationsVisibleForExpansion: $mNotificationsVisibleForExpansion") - pw.println("mVisibilityAmount: $mVisibilityAmount") - pw.println("mLinearVisibilityAmount: $mLinearVisibilityAmount") - pw.println("pulseExpanding: $pulseExpanding") - pw.println("state: ${StatusBarState.toString(state)}") - pw.println("fullyAwake: $fullyAwake") - pw.println("wakingUp: $wakingUp") - pw.println("willWakeUp: $willWakeUp") - pw.println("collapsedEnoughToHide: $collapsedEnoughToHide") - pw.println("pulsing: $pulsing") - pw.println("notificationsFullyHidden: $notificationsFullyHidden") - pw.println("canShowPulsingHuns: $canShowPulsingHuns") - } -} +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index ed186ab6a10b..8273d5737c2f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -33,7 +33,6 @@ import android.widget.LinearLayout.LayoutParams; import androidx.annotation.VisibleForTesting; import com.android.internal.statusbar.StatusBarIcon; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.demomode.DemoModeCommandReceiver; @@ -137,11 +136,12 @@ public interface StatusBarIconController { LinearLayout linearLayout, FeatureFlags featureFlags, StatusBarPipelineFlags statusBarPipelineFlags, - Provider<WifiViewModel> wifiViewModelProvider) { + Provider<WifiViewModel> wifiViewModelProvider, + DarkIconDispatcher darkIconDispatcher) { super(linearLayout, featureFlags, statusBarPipelineFlags, wifiViewModelProvider); mIconHPadding = mContext.getResources().getDimensionPixelSize( R.dimen.status_bar_icon_padding); - mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class); + mDarkIconDispatcher = darkIconDispatcher; } @Override @@ -198,20 +198,24 @@ public interface StatusBarIconController { private final FeatureFlags mFeatureFlags; private final StatusBarPipelineFlags mStatusBarPipelineFlags; private final Provider<WifiViewModel> mWifiViewModelProvider; + private final DarkIconDispatcher mDarkIconDispatcher; @Inject public Factory( FeatureFlags featureFlags, StatusBarPipelineFlags statusBarPipelineFlags, - Provider<WifiViewModel> wifiViewModelProvider) { + Provider<WifiViewModel> wifiViewModelProvider, + DarkIconDispatcher darkIconDispatcher) { mFeatureFlags = featureFlags; mStatusBarPipelineFlags = statusBarPipelineFlags; mWifiViewModelProvider = wifiViewModelProvider; + mDarkIconDispatcher = darkIconDispatcher; } public DarkIconManager create(LinearLayout group) { return new DarkIconManager( - group, mFeatureFlags, mStatusBarPipelineFlags, mWifiViewModelProvider); + group, mFeatureFlags, mStatusBarPipelineFlags, mWifiViewModelProvider, + mDarkIconDispatcher); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt index 77654273bde4..103f3fc21f91 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt @@ -46,7 +46,7 @@ import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.flow.shareIn +import kotlinx.coroutines.flow.stateIn /** * Provides data related to the wifi state. @@ -118,12 +118,19 @@ class WifiRepositoryImpl @Inject constructor( } } - trySend(WIFI_NETWORK_DEFAULT) connectivityManager.registerNetworkCallback(WIFI_NETWORK_CALLBACK_REQUEST, callback) awaitClose { connectivityManager.unregisterNetworkCallback(callback) } } - .shareIn(scope, started = SharingStarted.WhileSubscribed()) + // There will be multiple wifi icons in different places that will frequently + // subscribe/unsubscribe to flows as the views attach/detach. Using [stateIn] ensures that + // new subscribes will get the latest value immediately upon subscription. Otherwise, the + // views could show stale data. See b/244173280. + .stateIn( + scope, + started = SharingStarted.WhileSubscribed(), + initialValue = WIFI_NETWORK_DEFAULT + ) override val wifiActivity: Flow<WifiActivityModel> = if (wifiManager == null) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index 13c3df3acb69..c7ba5182eef8 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -48,7 +48,6 @@ import android.app.KeyguardManager; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; -import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.ColorStateList; import android.content.res.Configuration; @@ -248,6 +247,7 @@ public class VolumeDialogImpl implements VolumeDialog, private final ConfigurationController mConfigurationController; private final MediaOutputDialogFactory mMediaOutputDialogFactory; + private final VolumePanelFactory mVolumePanelFactory; private final ActivityStarter mActivityStarter; private boolean mShowing; @@ -279,6 +279,7 @@ public class VolumeDialogImpl implements VolumeDialog, DeviceProvisionedController deviceProvisionedController, ConfigurationController configurationController, MediaOutputDialogFactory mediaOutputDialogFactory, + VolumePanelFactory volumePanelFactory, ActivityStarter activityStarter, InteractionJankMonitor interactionJankMonitor) { mContext = @@ -290,6 +291,7 @@ public class VolumeDialogImpl implements VolumeDialog, mDeviceProvisionedController = deviceProvisionedController; mConfigurationController = configurationController; mMediaOutputDialogFactory = mediaOutputDialogFactory; + mVolumePanelFactory = volumePanelFactory; mActivityStarter = activityStarter; mShowActiveStreamOnly = showActiveStreamOnly(); mHasSeenODICaptionsTooltip = @@ -1045,10 +1047,9 @@ public class VolumeDialogImpl implements VolumeDialog, if (mSettingsIcon != null) { mSettingsIcon.setOnClickListener(v -> { Events.writeEvent(Events.EVENT_SETTINGS_CLICK); - Intent intent = new Intent(Settings.Panel.ACTION_VOLUME); dismissH(DISMISS_REASON_SETTINGS_CLICKED); mMediaOutputDialogFactory.dismiss(); - mActivityStarter.startActivity(intent, true /* dismissShade */); + mVolumePanelFactory.create(true /* aboveStatusBar */, null); }); } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java new file mode 100644 index 000000000000..2c74fb911688 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2022 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.volume; + +import android.bluetooth.BluetoothDevice; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; +import android.provider.SettingsSlicesContract; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.Button; + +import androidx.annotation.NonNull; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LifecycleRegistry; +import androidx.lifecycle.LiveData; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.slice.Slice; +import androidx.slice.SliceMetadata; +import androidx.slice.widget.EventInfo; +import androidx.slice.widget.SliceLiveData; + +import com.android.settingslib.bluetooth.A2dpProfile; +import com.android.settingslib.bluetooth.BluetoothUtils; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; +import com.android.settingslib.media.MediaOutputConstants; +import com.android.systemui.R; +import com.android.systemui.statusbar.phone.SystemUIDialog; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * Visual presentation of the volume panel dialog. + */ +public class VolumePanelDialog extends SystemUIDialog implements LifecycleOwner { + private static final String TAG = "VolumePanelDialog"; + + private static final int DURATION_SLICE_BINDING_TIMEOUT_MS = 200; + private static final int DEFAULT_SLICE_SIZE = 4; + + private RecyclerView mVolumePanelSlices; + private VolumePanelSlicesAdapter mVolumePanelSlicesAdapter; + private final LifecycleRegistry mLifecycleRegistry; + private final Handler mHandler = new Handler(Looper.getMainLooper()); + private final Map<Uri, LiveData<Slice>> mSliceLiveData = new LinkedHashMap<>(); + private final HashSet<Uri> mLoadedSlices = new HashSet<>(); + private boolean mSlicesReadyToLoad; + private LocalBluetoothProfileManager mProfileManager; + + public VolumePanelDialog(Context context, boolean aboveStatusBar) { + super(context); + mLifecycleRegistry = new LifecycleRegistry(this); + if (!aboveStatusBar) { + getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Log.d(TAG, "onCreate"); + + View dialogView = LayoutInflater.from(getContext()).inflate(R.layout.volume_panel_dialog, + null); + final Window window = getWindow(); + window.setContentView(dialogView); + + Button doneButton = dialogView.findViewById(R.id.done_button); + doneButton.setOnClickListener(v -> dismiss()); + Button settingsButton = dialogView.findViewById(R.id.settings_button); + settingsButton.setOnClickListener(v -> { + getContext().startActivity(new Intent(Settings.ACTION_SOUND_SETTINGS).addFlags( + Intent.FLAG_ACTIVITY_NEW_TASK)); + dismiss(); + }); + + LocalBluetoothManager localBluetoothManager = LocalBluetoothManager.getInstance( + getContext(), null); + if (localBluetoothManager != null) { + mProfileManager = localBluetoothManager.getProfileManager(); + } + + mVolumePanelSlices = dialogView.findViewById(R.id.volume_panel_parent_layout); + mVolumePanelSlices.setLayoutManager(new LinearLayoutManager(getContext())); + + loadAllSlices(); + + mLifecycleRegistry.setCurrentState(Lifecycle.State.CREATED); + } + + private void loadAllSlices() { + mSliceLiveData.clear(); + mLoadedSlices.clear(); + final List<Uri> sliceUris = getSlices(); + + for (Uri uri : sliceUris) { + final LiveData<Slice> sliceLiveData = SliceLiveData.fromUri(getContext(), uri, + (int type, Throwable source) -> { + if (!removeSliceLiveData(uri)) { + mLoadedSlices.add(uri); + } + }); + + // Add slice first to make it in order. Will remove it later if there's an error. + mSliceLiveData.put(uri, sliceLiveData); + + sliceLiveData.observe(this, slice -> { + if (mLoadedSlices.contains(uri)) { + return; + } + Log.d(TAG, "received slice: " + (slice == null ? null : slice.getUri())); + final SliceMetadata metadata = SliceMetadata.from(getContext(), slice); + if (slice == null || metadata.isErrorSlice()) { + if (!removeSliceLiveData(uri)) { + mLoadedSlices.add(uri); + } + } else if (metadata.getLoadingState() == SliceMetadata.LOADED_ALL) { + mLoadedSlices.add(uri); + } else { + mHandler.postDelayed(() -> { + mLoadedSlices.add(uri); + setupAdapterWhenReady(); + }, DURATION_SLICE_BINDING_TIMEOUT_MS); + } + + setupAdapterWhenReady(); + }); + } + } + + private void setupAdapterWhenReady() { + if (mLoadedSlices.size() == mSliceLiveData.size() && !mSlicesReadyToLoad) { + mSlicesReadyToLoad = true; + mVolumePanelSlicesAdapter = new VolumePanelSlicesAdapter(this, mSliceLiveData); + mVolumePanelSlicesAdapter.setOnSliceActionListener((eventInfo, sliceItem) -> { + if (eventInfo.actionType == EventInfo.ACTION_TYPE_SLIDER) { + return; + } + this.dismiss(); + }); + if (mSliceLiveData.size() < DEFAULT_SLICE_SIZE) { + mVolumePanelSlices.setMinimumHeight(0); + } + mVolumePanelSlices.setAdapter(mVolumePanelSlicesAdapter); + } + } + + private boolean removeSliceLiveData(Uri uri) { + boolean removed = false; + // Keeps observe media output slice + if (!uri.equals(MEDIA_OUTPUT_INDICATOR_SLICE_URI)) { + Log.d(TAG, "remove uri: " + uri); + removed = mSliceLiveData.remove(uri) != null; + if (mVolumePanelSlicesAdapter != null) { + mVolumePanelSlicesAdapter.updateDataSet(new ArrayList<>(mSliceLiveData.values())); + } + } + return removed; + } + + @Override + protected void onStart() { + super.onStart(); + Log.d(TAG, "onStart"); + mLifecycleRegistry.setCurrentState(Lifecycle.State.STARTED); + mLifecycleRegistry.setCurrentState(Lifecycle.State.RESUMED); + } + + @Override + protected void onStop() { + super.onStop(); + Log.d(TAG, "onStop"); + mLifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED); + } + + private List<Uri> getSlices() { + final List<Uri> uris = new ArrayList<>(); + uris.add(REMOTE_MEDIA_SLICE_URI); + uris.add(VOLUME_MEDIA_URI); + Uri controlUri = getExtraControlUri(); + if (controlUri != null) { + Log.d(TAG, "add extra control slice"); + uris.add(controlUri); + } + uris.add(MEDIA_OUTPUT_INDICATOR_SLICE_URI); + uris.add(VOLUME_CALL_URI); + uris.add(VOLUME_RINGER_URI); + uris.add(VOLUME_ALARM_URI); + return uris; + } + + private static final String SETTINGS_SLICE_AUTHORITY = "com.android.settings.slices"; + private static final Uri REMOTE_MEDIA_SLICE_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SETTINGS_SLICE_AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) + .appendPath(MediaOutputConstants.KEY_REMOTE_MEDIA) + .build(); + private static final Uri VOLUME_MEDIA_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SETTINGS_SLICE_AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) + .appendPath("media_volume") + .build(); + private static final Uri MEDIA_OUTPUT_INDICATOR_SLICE_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SETTINGS_SLICE_AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_INTENT) + .appendPath("media_output_indicator") + .build(); + private static final Uri VOLUME_CALL_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SETTINGS_SLICE_AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) + .appendPath("call_volume") + .build(); + private static final Uri VOLUME_RINGER_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SETTINGS_SLICE_AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) + .appendPath("ring_volume") + .build(); + private static final Uri VOLUME_ALARM_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SETTINGS_SLICE_AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) + .appendPath("alarm_volume") + .build(); + + private Uri getExtraControlUri() { + Uri controlUri = null; + final BluetoothDevice bluetoothDevice = findActiveDevice(); + if (bluetoothDevice != null) { + // The control slice width = dialog width - horizontal padding of two sides + final int dialogWidth = + getWindow().getWindowManager().getCurrentWindowMetrics().getBounds().width(); + final int controlSliceWidth = dialogWidth + - getContext().getResources().getDimensionPixelSize( + R.dimen.volume_panel_slice_horizontal_padding) * 2; + final String uri = BluetoothUtils.getControlUriMetaData(bluetoothDevice); + if (!TextUtils.isEmpty(uri)) { + try { + controlUri = Uri.parse(uri + controlSliceWidth); + } catch (NullPointerException exception) { + Log.d(TAG, "unable to parse extra control uri"); + controlUri = null; + } + } + } + return controlUri; + } + + private BluetoothDevice findActiveDevice() { + if (mProfileManager != null) { + final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile(); + if (a2dpProfile != null) { + return a2dpProfile.getActiveDevice(); + } + } + return null; + } + + @NonNull + @Override + public Lifecycle getLifecycle() { + return mLifecycleRegistry; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialogReceiver.kt b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialogReceiver.kt new file mode 100644 index 000000000000..f11d5d18ac84 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialogReceiver.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 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.volume + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.provider.Settings +import android.text.TextUtils +import android.util.Log +import javax.inject.Inject + +private const val TAG = "VolumePanelDialogReceiver" +private const val LAUNCH_ACTION = "com.android.systemui.action.LAUNCH_VOLUME_PANEL_DIALOG" +private const val DISMISS_ACTION = "com.android.systemui.action.DISMISS_VOLUME_PANEL_DIALOG" + +/** + * BroadcastReceiver for handling volume panel dialog intent + */ +class VolumePanelDialogReceiver @Inject constructor( + private val volumePanelFactory: VolumePanelFactory +) : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + Log.d(TAG, "onReceive intent" + intent.action) + if (TextUtils.equals(LAUNCH_ACTION, intent.action) || + TextUtils.equals(Settings.Panel.ACTION_VOLUME, intent.action)) { + volumePanelFactory.create(true, null) + } else if (TextUtils.equals(DISMISS_ACTION, intent.action)) { + volumePanelFactory.dismiss() + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt new file mode 100644 index 000000000000..c2fafbf9f55b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2022 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.volume + +import android.content.Context +import android.util.Log +import android.view.View +import com.android.systemui.animation.DialogLaunchAnimator +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject + +private const val TAG = "VolumePanelFactory" +private val DEBUG = Log.isLoggable(TAG, Log.DEBUG) + +/** + * Factory to create [VolumePanelDialog] objects. This is the dialog that allows the user to adjust + * multiple streams with sliders. + */ +@SysUISingleton +class VolumePanelFactory @Inject constructor( + private val context: Context, + private val dialogLaunchAnimator: DialogLaunchAnimator +) { + companion object { + var volumePanelDialog: VolumePanelDialog? = null + } + + /** Creates a [VolumePanelDialog]. The dialog will be animated from [view] if it is not null. */ + fun create(aboveStatusBar: Boolean, view: View? = null) { + if (volumePanelDialog?.isShowing == true) { + return + } + + val dialog = VolumePanelDialog(context, aboveStatusBar) + volumePanelDialog = dialog + + // Show the dialog. + if (view != null) { + dialogLaunchAnimator.showFromView(dialog, view, animateBackgroundBoundsChange = true) + } else { + dialog.show() + } + } + + /** Dismiss [VolumePanelDialog] if exist. */ + fun dismiss() { + if (DEBUG) { + Log.d(TAG, "dismiss dialog") + } + volumePanelDialog?.dismiss() + volumePanelDialog = null + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelSlicesAdapter.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelSlicesAdapter.java new file mode 100644 index 000000000000..23714021a2cc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelSlicesAdapter.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2022 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.volume; + +import static android.app.slice.Slice.HINT_ERROR; +import static android.app.slice.SliceItem.FORMAT_SLICE; + +import android.content.Context; +import android.net.Uri; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LiveData; +import androidx.recyclerview.widget.RecyclerView; +import androidx.slice.Slice; +import androidx.slice.SliceItem; +import androidx.slice.widget.SliceView; + +import com.android.systemui.R; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * RecyclerView adapter for Slices in Settings Panels. + */ +public class VolumePanelSlicesAdapter extends + RecyclerView.Adapter<VolumePanelSlicesAdapter.SliceRowViewHolder> { + + private final List<LiveData<Slice>> mSliceLiveData; + private final LifecycleOwner mLifecycleOwner; + private SliceView.OnSliceActionListener mOnSliceActionListener; + + public VolumePanelSlicesAdapter(LifecycleOwner lifecycleOwner, + Map<Uri, LiveData<Slice>> sliceLiveData) { + mLifecycleOwner = lifecycleOwner; + mSliceLiveData = new ArrayList<>(sliceLiveData.values()); + } + + @NonNull + @Override + public SliceRowViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) { + final Context context = viewGroup.getContext(); + final LayoutInflater inflater = LayoutInflater.from(context); + View view = inflater.inflate(R.layout.volume_panel_slice_slider_row, viewGroup, false); + return new SliceRowViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull SliceRowViewHolder sliceRowViewHolder, int position) { + sliceRowViewHolder.onBind(mSliceLiveData.get(position), position); + } + + @Override + public int getItemCount() { + return mSliceLiveData.size(); + } + + @Override + public int getItemViewType(int position) { + return position; + } + + void setOnSliceActionListener(SliceView.OnSliceActionListener listener) { + mOnSliceActionListener = listener; + } + + void updateDataSet(ArrayList<LiveData<Slice>> list) { + mSliceLiveData.clear(); + mSliceLiveData.addAll(list); + notifyDataSetChanged(); + } + + /** + * ViewHolder for binding Slices to SliceViews. + */ + public class SliceRowViewHolder extends RecyclerView.ViewHolder { + + private final SliceView mSliceView; + + public SliceRowViewHolder(View view) { + super(view); + mSliceView = view.findViewById(R.id.slice_view); + mSliceView.setMode(SliceView.MODE_LARGE); + mSliceView.setShowTitleItems(true); + mSliceView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + mSliceView.setOnSliceActionListener(mOnSliceActionListener); + } + + /** + * Called when the view is displayed. + */ + public void onBind(LiveData<Slice> sliceLiveData, int position) { + sliceLiveData.observe(mLifecycleOwner, mSliceView); + + // Do not show the divider above media devices switcher slice per request + final Slice slice = sliceLiveData.getValue(); + + // Hides slice which reports with error hint or not contain any slice sub-item. + if (slice == null || !isValidSlice(slice)) { + mSliceView.setVisibility(View.GONE); + } else { + mSliceView.setVisibility(View.VISIBLE); + } + } + + private boolean isValidSlice(Slice slice) { + if (slice.getHints().contains(HINT_ERROR)) { + return false; + } + for (SliceItem item : slice.getItems()) { + if (item.getFormat().equals(FORMAT_SLICE)) { + return true; + } + } + return false; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java index f3855bddfe48..c5792b923e48 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java @@ -30,6 +30,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.volume.VolumeComponent; import com.android.systemui.volume.VolumeDialogComponent; import com.android.systemui.volume.VolumeDialogImpl; +import com.android.systemui.volume.VolumePanelFactory; import dagger.Binds; import dagger.Module; @@ -52,6 +53,7 @@ public interface VolumeModule { DeviceProvisionedController deviceProvisionedController, ConfigurationController configurationController, MediaOutputDialogFactory mediaOutputDialogFactory, + VolumePanelFactory volumePanelFactory, ActivityStarter activityStarter, InteractionJankMonitor interactionJankMonitor) { VolumeDialogImpl impl = new VolumeDialogImpl( @@ -61,6 +63,7 @@ public interface VolumeModule { deviceProvisionedController, configurationController, mediaOutputDialogFactory, + volumePanelFactory, activityStarter, interactionJankMonitor); impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java index aecec9d100cc..d68e8bd36c40 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java @@ -387,6 +387,33 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { } @Test + public void onResume_sideFpsHintShouldBeShown_sideFpsHintShown() { + setupGetSecurityView(); + setupConditionsToEnableSideFpsHint(); + mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); + reset(mSidefpsController); + + mKeyguardSecurityContainerController.onResume(0); + + verify(mSidefpsController).show(); + verify(mSidefpsController, never()).hide(); + } + + @Test + public void onResume_sideFpsHintShouldNotBeShown_sideFpsHintHidden() { + setupGetSecurityView(); + setupConditionsToEnableSideFpsHint(); + setSideFpsHintEnabledFromResources(false); + mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); + reset(mSidefpsController); + + mKeyguardSecurityContainerController.onResume(0); + + verify(mSidefpsController).hide(); + verify(mSidefpsController, never()).show(); + } + + @Test public void showNextSecurityScreenOrFinish_setsSecurityScreenToPinAfterSimPinUnlock() { // GIVEN the current security method is SimPin when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt new file mode 100644 index 000000000000..6b1ef389a98e --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt @@ -0,0 +1,179 @@ +package com.android.systemui + +import android.content.ComponentName +import android.content.Context +import android.content.pm.PackageManager +import android.content.res.Resources +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.Flag +import com.android.systemui.flags.FlagListenable +import com.android.systemui.flags.Flags +import com.android.systemui.flags.UnreleasedFlag +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.kotlinArgumentCaptor +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.cancel +import kotlinx.coroutines.test.TestCoroutineDispatcher +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.clearInvocations +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyZeroInteractions +import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations + +@OptIn(ExperimentalCoroutinesApi::class) +@RunWith(AndroidTestingRunner::class) +@SmallTest +class ChooserSelectorTest : SysuiTestCase() { + + private val flagListener = kotlinArgumentCaptor<FlagListenable.Listener>() + + private val testDispatcher = TestCoroutineDispatcher() + private val testScope = CoroutineScope(testDispatcher) + + private lateinit var chooserSelector: ChooserSelector + + @Mock private lateinit var mockContext: Context + @Mock private lateinit var mockPackageManager: PackageManager + @Mock private lateinit var mockResources: Resources + @Mock private lateinit var mockFeatureFlags: FeatureFlags + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + + `when`(mockContext.packageManager).thenReturn(mockPackageManager) + `when`(mockContext.resources).thenReturn(mockResources) + `when`(mockResources.getString(anyInt())).thenReturn( + ComponentName("TestPackage", "TestClass").flattenToString()) + + chooserSelector = ChooserSelector(mockContext, mockFeatureFlags, testScope, testDispatcher) + } + + @After + fun tearDown() { + testDispatcher.cleanupTestCoroutines() + } + + @Test + fun initialize_registersFlagListenerUntilScopeCancelled() { + // Arrange + + // Act + chooserSelector.start() + + // Assert + verify(mockFeatureFlags).addListener( + eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture()) + verify(mockFeatureFlags, never()).removeListener(any()) + + // Act + testScope.cancel() + + // Assert + verify(mockFeatureFlags).removeListener(eq(flagListener.value)) + } + + @Test + fun initialize_enablesUnbundledChooser_whenFlagEnabled() { + // Arrange + `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) + + // Act + chooserSelector.start() + + // Assert + verify(mockPackageManager).setComponentEnabledSetting( + eq(ComponentName("TestPackage", "TestClass")), + eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED), + anyInt()) + } + + @Test + fun initialize_disablesUnbundledChooser_whenFlagDisabled() { + // Arrange + `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) + + // Act + chooserSelector.start() + + // Assert + verify(mockPackageManager).setComponentEnabledSetting( + eq(ComponentName("TestPackage", "TestClass")), + eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), + anyInt()) + } + + @Test + fun enablesUnbundledChooser_whenFlagBecomesEnabled() { + // Arrange + `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) + chooserSelector.start() + verify(mockFeatureFlags).addListener( + eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture()) + verify(mockPackageManager, never()).setComponentEnabledSetting( + any(), eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED), anyInt()) + + // Act + `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) + flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id)) + + // Assert + verify(mockPackageManager).setComponentEnabledSetting( + eq(ComponentName("TestPackage", "TestClass")), + eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED), + anyInt()) + } + + @Test + fun disablesUnbundledChooser_whenFlagBecomesDisabled() { + // Arrange + `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true) + chooserSelector.start() + verify(mockFeatureFlags).addListener( + eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture()) + verify(mockPackageManager, never()).setComponentEnabledSetting( + any(), eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), anyInt()) + + // Act + `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) + flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id)) + + // Assert + verify(mockPackageManager).setComponentEnabledSetting( + eq(ComponentName("TestPackage", "TestClass")), + eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), + anyInt()) + } + + @Test + fun doesNothing_whenAnotherFlagChanges() { + // Arrange + `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) + chooserSelector.start() + verify(mockFeatureFlags).addListener( + eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture()) + clearInvocations(mockPackageManager) + + // Act + `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false) + flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id + 1)) + + // Assert + verifyZeroInteractions(mockPackageManager) + } + + private class TestFlagEvent(override val flagId: Int) : FlagListenable.FlagEvent { + override fun requestNoRestart() {} + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java index 7d54758acee7..fa8f88a08368 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java @@ -43,7 +43,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; -import java.util.Arrays; +import java.util.Collections; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -61,9 +61,6 @@ public class SmartSpaceComplicationTest extends SysuiTestCase { private SmartSpaceComplication mComplication; @Mock - private ComplicationViewModel mComplicationViewModel; - - @Mock private View mBcSmartspaceView; @Before @@ -125,12 +122,12 @@ public class SmartSpaceComplicationTest extends SysuiTestCase { // Test final SmartspaceTarget target = Mockito.mock(SmartspaceTarget.class); - listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList(target)); + listenerCaptor.getValue().onSmartspaceTargetsUpdated(Collections.singletonList(target)); verify(mDreamOverlayStateController).addComplication(eq(mComplication)); } @Test - public void testOverlayActive_targetsEmpty_removesComplication() { + public void testOverlayActive_targetsEmpty_addsComplication() { final SmartSpaceComplication.Registrant registrant = getRegistrant(); registrant.start(); @@ -145,13 +142,9 @@ public class SmartSpaceComplicationTest extends SysuiTestCase { ArgumentCaptor.forClass(BcSmartspaceDataPlugin.SmartspaceTargetListener.class); verify(mSmartspaceController).addListener(listenerCaptor.capture()); - final SmartspaceTarget target = Mockito.mock(SmartspaceTarget.class); - listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList(target)); - verify(mDreamOverlayStateController).addComplication(eq(mComplication)); - // Test - listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList()); - verify(mDreamOverlayStateController).removeComplication(eq(mComplication)); + listenerCaptor.getValue().onSmartspaceTargetsUpdated(Collections.emptyList()); + verify(mDreamOverlayStateController).addComplication(eq(mComplication)); } @Test @@ -170,8 +163,7 @@ public class SmartSpaceComplicationTest extends SysuiTestCase { ArgumentCaptor.forClass(BcSmartspaceDataPlugin.SmartspaceTargetListener.class); verify(mSmartspaceController).addListener(listenerCaptor.capture()); - final SmartspaceTarget target = Mockito.mock(SmartspaceTarget.class); - listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList(target)); + listenerCaptor.getValue().onSmartspaceTargetsUpdated(Collections.emptyList()); verify(mDreamOverlayStateController).addComplication(eq(mComplication)); // Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt index ff579a1cc4aa..318f2bc1c227 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt @@ -41,7 +41,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() { * specified. If not, an exception is thrown. */ @Test - fun throwsIfUnspecifiedFlagIsAccessed() { + fun accessingUnspecifiedFlags_throwsException() { val flags: FeatureFlags = FakeFeatureFlags() try { assertThat(flags.isEnabled(Flags.TEAMFOOD)).isFalse() @@ -88,7 +88,7 @@ class FakeFeatureFlagsTest : SysuiTestCase() { } @Test - fun specifiedFlagsReturnCorrectValues() { + fun specifiedFlags_returnCorrectValues() { val flags = FakeFeatureFlags() flags.set(unreleasedFlag, false) flags.set(releasedFlag, false) @@ -114,4 +114,125 @@ class FakeFeatureFlagsTest : SysuiTestCase() { assertThat(flags.isEnabled(sysPropBooleanFlag)).isTrue() assertThat(flags.getString(resourceStringFlag)).isEqualTo("Android") } + + @Test + fun listenerForBooleanFlag_calledOnlyWhenFlagChanged() { + val flags = FakeFeatureFlags() + val listener = VerifyingListener() + flags.addListener(unreleasedFlag, listener) + + flags.set(unreleasedFlag, true) + flags.set(unreleasedFlag, true) + flags.set(unreleasedFlag, false) + flags.set(unreleasedFlag, false) + + listener.verifyInOrder(unreleasedFlag.id, unreleasedFlag.id) + } + + @Test + fun listenerForStringFlag_calledOnlyWhenFlagChanged() { + val flags = FakeFeatureFlags() + val listener = VerifyingListener() + flags.addListener(stringFlag, listener) + + flags.set(stringFlag, "Test") + flags.set(stringFlag, "Test") + + listener.verifyInOrder(stringFlag.id) + } + + @Test + fun listenerForBooleanFlag_notCalledAfterRemoved() { + val flags = FakeFeatureFlags() + val listener = VerifyingListener() + flags.addListener(unreleasedFlag, listener) + flags.set(unreleasedFlag, true) + flags.removeListener(listener) + flags.set(unreleasedFlag, false) + + listener.verifyInOrder(unreleasedFlag.id) + } + + @Test + fun listenerForStringFlag_notCalledAfterRemoved() { + val flags = FakeFeatureFlags() + val listener = VerifyingListener() + + flags.addListener(stringFlag, listener) + flags.set(stringFlag, "Test") + flags.removeListener(listener) + flags.set(stringFlag, "Other") + + listener.verifyInOrder(stringFlag.id) + } + + @Test + fun listenerForMultipleFlags_calledWhenFlagsChange() { + val flags = FakeFeatureFlags() + val listener = VerifyingListener() + flags.addListener(unreleasedFlag, listener) + flags.addListener(releasedFlag, listener) + + flags.set(releasedFlag, true) + flags.set(unreleasedFlag, true) + + listener.verifyInOrder(releasedFlag.id, unreleasedFlag.id) + } + + @Test + fun listenerForMultipleFlags_notCalledAfterRemoved() { + val flags = FakeFeatureFlags() + val listener = VerifyingListener() + + flags.addListener(unreleasedFlag, listener) + flags.addListener(releasedFlag, listener) + flags.set(releasedFlag, true) + flags.set(unreleasedFlag, true) + flags.removeListener(listener) + flags.set(releasedFlag, false) + flags.set(unreleasedFlag, false) + + listener.verifyInOrder(releasedFlag.id, unreleasedFlag.id) + } + + @Test + fun multipleListenersForSingleFlag_allAreCalledWhenChanged() { + val flags = FakeFeatureFlags() + val listener1 = VerifyingListener() + val listener2 = VerifyingListener() + flags.addListener(releasedFlag, listener1) + flags.addListener(releasedFlag, listener2) + + flags.set(releasedFlag, true) + + listener1.verifyInOrder(releasedFlag.id) + listener2.verifyInOrder(releasedFlag.id) + } + + @Test + fun multipleListenersForSingleFlag_removedListenerNotCalledAfterRemoval() { + val flags = FakeFeatureFlags() + val listener1 = VerifyingListener() + val listener2 = VerifyingListener() + flags.addListener(releasedFlag, listener1) + flags.addListener(releasedFlag, listener2) + + flags.set(releasedFlag, true) + flags.removeListener(listener2) + flags.set(releasedFlag, false) + + listener1.verifyInOrder(releasedFlag.id, releasedFlag.id) + listener2.verifyInOrder(releasedFlag.id) + } + + class VerifyingListener : FlagListenable.Listener { + var flagEventIds = mutableListOf<Int>() + override fun onFlagChanged(event: FlagListenable.FlagEvent) { + flagEventIds.add(event.flagId) + } + + fun verifyInOrder(vararg eventIds: Int) { + assertThat(flagEventIds).containsExactlyElementsIn(eventIds.asList()) + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index 178502269e73..bef46953395b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -1051,6 +1051,17 @@ public class MediaControlPanelTest : SysuiTestCase() { } @Test + fun bindDeviceWithNullName() { + val fallbackString = context.getResources().getString(R.string.media_seamless_other_device) + player.attachPlayer(viewHolder) + val state = mediaData.copy(device = device.copy(name = null)) + player.bindPlayer(state, PACKAGE) + assertThat(seamless.isEnabled()).isTrue() + assertThat(seamlessText.getText()).isEqualTo(fallbackString) + assertThat(seamless.contentDescription).isEqualTo(fallbackString) + } + + @Test fun bindDeviceResumptionPlayer() { player.attachPlayer(viewHolder) val state = mediaData.copy(resumption = true) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt index d1ed8e983cdd..f9c7d2d5cb41 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt @@ -31,7 +31,6 @@ import com.android.systemui.statusbar.SbnBuilder import com.android.systemui.tuner.TunerService import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any -import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock @@ -108,6 +107,7 @@ class MediaDataManagerTest : SysuiTestCase() { private val clock = FakeSystemClock() @Mock private lateinit var tunerService: TunerService @Captor lateinit var tunableCaptor: ArgumentCaptor<TunerService.Tunable> + @Captor lateinit var callbackCaptor: ArgumentCaptor<(String, PlaybackState) -> Unit> private val instanceIdSequence = InstanceIdSequenceFake(1 shl 20) @@ -974,7 +974,6 @@ class MediaDataManagerTest : SysuiTestCase() { fun testPlaybackStateChange_keyExists_callsListener() { // Notification has been added addNotificationAndLoad() - val callbackCaptor = argumentCaptor<(String, PlaybackState) -> Unit>() verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor) // Callback gets an updated state @@ -992,7 +991,6 @@ class MediaDataManagerTest : SysuiTestCase() { @Test fun testPlaybackStateChange_keyDoesNotExist_doesNothing() { val state = PlaybackState.Builder().build() - val callbackCaptor = argumentCaptor<(String, PlaybackState) -> Unit>() verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor) // No media added with this key @@ -1013,7 +1011,6 @@ class MediaDataManagerTest : SysuiTestCase() { // And then get a state update val state = PlaybackState.Builder().build() - val callbackCaptor = argumentCaptor<(String, PlaybackState) -> Unit>() verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor) // Then no changes are made @@ -1022,6 +1019,83 @@ class MediaDataManagerTest : SysuiTestCase() { anyBoolean()) } + @Test + fun testPlaybackState_PauseWhenFlagTrue_keyExists_callsListener() { + whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true) + val state = PlaybackState.Builder() + .setState(PlaybackState.STATE_PAUSED, 0L, 1f) + .build() + whenever(controller.playbackState).thenReturn(state) + + addNotificationAndLoad() + verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor) + callbackCaptor.value.invoke(KEY, state) + + verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), + capture(mediaDataCaptor), eq(true), eq(0), eq(false)) + assertThat(mediaDataCaptor.value.isPlaying).isFalse() + assertThat(mediaDataCaptor.value.semanticActions).isNotNull() + } + + @Test + fun testPlaybackState_PauseStateAfterAddingResumption_keyExists_callsListener() { + val desc = MediaDescription.Builder().run { + setTitle(SESSION_TITLE) + build() + } + val state = PlaybackState.Builder() + .setState(PlaybackState.STATE_PAUSED, 0L, 1f) + .setActions(PlaybackState.ACTION_PLAY_PAUSE) + .build() + + // Add resumption controls in order to have semantic actions. + // To make sure that they are not null after changing state. + mediaDataManager.addResumptionControls( + USER_ID, + desc, + Runnable {}, + session.sessionToken, + APP_NAME, + pendingIntent, + PACKAGE_NAME + ) + backgroundExecutor.runAllReady() + foregroundExecutor.runAllReady() + + verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor) + callbackCaptor.value.invoke(PACKAGE_NAME, state) + + verify(listener) + .onMediaDataLoaded( + eq(PACKAGE_NAME), + eq(PACKAGE_NAME), + capture(mediaDataCaptor), + eq(true), + eq(0), + eq(false) + ) + assertThat(mediaDataCaptor.value.isPlaying).isFalse() + assertThat(mediaDataCaptor.value.semanticActions).isNotNull() + } + + @Test + fun testPlaybackStateNull_Pause_keyExists_callsListener() { + whenever(controller.playbackState).thenReturn(null) + val state = PlaybackState.Builder() + .setState(PlaybackState.STATE_PAUSED, 0L, 1f) + .setActions(PlaybackState.ACTION_PLAY_PAUSE) + .build() + + addNotificationAndLoad() + verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor) + callbackCaptor.value.invoke(KEY, state) + + verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), + capture(mediaDataCaptor), eq(true), eq(0), eq(false)) + assertThat(mediaDataCaptor.value.isPlaying).isFalse() + assertThat(mediaDataCaptor.value.semanticActions).isNull() + } + /** * Helper function to add a media notification and capture the resulting MediaData */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt index ee104262dc29..121c8946d164 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt @@ -59,8 +59,8 @@ import org.mockito.Mockito.reset import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions -import org.mockito.junit.MockitoJUnit import org.mockito.Mockito.`when` as whenever +import org.mockito.junit.MockitoJUnit private const val KEY = "TEST_KEY" private const val KEY_OLD = "TEST_KEY_OLD" @@ -402,9 +402,10 @@ public class MediaDeviceManagerTest : SysuiTestCase() { manager.onMediaDataLoaded(KEY, null, mediaData) fakeBgExecutor.runAllReady() fakeFgExecutor.runAllReady() - // THEN the device is disabled + // THEN the device is disabled and name is set to null val data = captureDeviceData(KEY) assertThat(data.enabled).isFalse() + assertThat(data.name).isNull() } @Test @@ -421,9 +422,10 @@ public class MediaDeviceManagerTest : SysuiTestCase() { deviceCallback.onSelectedDeviceStateChanged(device, 1) fakeBgExecutor.runAllReady() fakeFgExecutor.runAllReady() - // THEN the device is disabled + // THEN the device is disabled and name is set to null val data = captureDeviceData(KEY) assertThat(data.enabled).isFalse() + assertThat(data.name).isNull() } @Test @@ -440,9 +442,24 @@ public class MediaDeviceManagerTest : SysuiTestCase() { deviceCallback.onDeviceListUpdate(mutableListOf(device)) fakeBgExecutor.runAllReady() fakeFgExecutor.runAllReady() - // THEN the device is disabled + // THEN the device is disabled and name is set to null val data = captureDeviceData(KEY) assertThat(data.enabled).isFalse() + assertThat(data.name).isNull() + } + + @Test + fun mr2ReturnsRouteWithNullName_useLocalDeviceName() { + // GIVEN that MR2Manager returns a routing session that does not have a name + whenever(route.name).thenReturn(null) + // WHEN a notification is added + manager.onMediaDataLoaded(KEY, null, mediaData) + fakeBgExecutor.runAllReady() + fakeFgExecutor.runAllReady() + // THEN the device is enabled and uses the current connected device name + val data = captureDeviceData(KEY) + assertThat(data.name).isEqualTo(DEVICE_NAME) + assertThat(data.enabled).isTrue() } @Test @@ -647,12 +664,14 @@ public class MediaDeviceManagerTest : SysuiTestCase() { override fun onPlaybackStopped(reason: Int, broadcastId: Int) {} override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {} override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) {} - override fun onBroadcastMetadataChanged(broadcastId: Int, - metadata: BluetoothLeBroadcastMetadata) {} + override fun onBroadcastMetadataChanged( + broadcastId: Int, + metadata: BluetoothLeBroadcastMetadata + ) {} } bluetoothLeBroadcast.registerCallback(fakeFgExecutor, callback) - return callback; + return callback } fun setupLeAudioConfiguration(isLeAudio: Boolean) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt index 1061e3c6b0d5..fa47a746f8ba 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt @@ -35,7 +35,9 @@ import com.android.internal.logging.testing.UiEventLoggerFake import com.android.internal.statusbar.IUndoMediaTransferCallback import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.classifier.FalsingCollector import com.android.systemui.media.taptotransfer.common.MediaTttLogger +import com.android.systemui.plugins.FalsingManager import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.concurrency.FakeExecutor @@ -48,11 +50,12 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.verify -import org.mockito.MockitoAnnotations import org.mockito.Mockito.`when` as whenever +import org.mockito.MockitoAnnotations @SmallTest @RunWith(AndroidTestingRunner::class) @@ -78,6 +81,10 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { private lateinit var viewUtil: ViewUtil @Mock private lateinit var commandQueue: CommandQueue + @Mock + private lateinit var falsingManager: FalsingManager + @Mock + private lateinit var falsingCollector: FalsingCollector private lateinit var commandQueueCallback: CommandQueue.Callbacks private lateinit var fakeAppIconDrawable: Drawable private lateinit var fakeClock: FakeSystemClock @@ -115,7 +122,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { accessibilityManager, configurationController, powerManager, - senderUiEventLogger + senderUiEventLogger, + falsingManager, + falsingCollector ) val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java) @@ -421,6 +430,38 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { } @Test + fun transferToReceiverSucceeded_withUndoRunnable_falseTap_callbackNotRun() { + whenever(falsingManager.isFalseTap(anyInt())).thenReturn(true) + var undoCallbackCalled = false + val undoCallback = object : IUndoMediaTransferCallback.Stub() { + override fun onUndoTriggered() { + undoCallbackCalled = true + } + } + + controllerSender.displayChip(transferToReceiverSucceeded(undoCallback)) + getChipView().getUndoButton().performClick() + + assertThat(undoCallbackCalled).isFalse() + } + + @Test + fun transferToReceiverSucceeded_withUndoRunnable_realTap_callbackRun() { + whenever(falsingManager.isFalseTap(anyInt())).thenReturn(false) + var undoCallbackCalled = false + val undoCallback = object : IUndoMediaTransferCallback.Stub() { + override fun onUndoTriggered() { + undoCallbackCalled = true + } + } + + controllerSender.displayChip(transferToReceiverSucceeded(undoCallback)) + getChipView().getUndoButton().performClick() + + assertThat(undoCallbackCalled).isTrue() + } + + @Test fun transferToReceiverSucceeded_undoButtonClick_switchesToTransferToThisDeviceTriggered() { val undoCallback = object : IUndoMediaTransferCallback.Stub() { override fun onUndoTriggered() {} diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt index 48fbd354b98d..073c23cec569 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt @@ -23,6 +23,7 @@ import android.graphics.Insets import android.graphics.Rect import android.hardware.HardwareBuffer import android.os.Bundle +import android.os.UserHandle import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN @@ -97,7 +98,7 @@ class RequestProcessorTest { policy.setManagedProfile(USER_ID, false) policy.setDisplayContentInfo( policy.getDefaultDisplayId(), - DisplayContentInfo(component, bounds, USER_ID, TASK_ID)) + DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID)) val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD) val processor = RequestProcessor(imageCapture, policy, flags, scope) @@ -120,7 +121,7 @@ class RequestProcessorTest { // Indicate that the primary content belongs to a manged profile policy.setManagedProfile(USER_ID, true) policy.setDisplayContentInfo(policy.getDefaultDisplayId(), - DisplayContentInfo(component, bounds, USER_ID, TASK_ID)) + DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID)) val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD) val processor = RequestProcessor(imageCapture, policy, flags, scope) @@ -160,7 +161,7 @@ class RequestProcessorTest { policy.setManagedProfile(USER_ID, false) policy.setDisplayContentInfo(policy.getDefaultDisplayId(), - DisplayContentInfo(component, bounds, USER_ID, TASK_ID)) + DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID)) val processedRequest = processor.process(request) @@ -183,7 +184,7 @@ class RequestProcessorTest { // Indicate that the primary content belongs to a manged profile policy.setManagedProfile(USER_ID, true) policy.setDisplayContentInfo(policy.getDefaultDisplayId(), - DisplayContentInfo(component, bounds, USER_ID, TASK_ID)) + DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID)) val processedRequest = processor.process(request) diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt new file mode 100644 index 000000000000..17396b13036c --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2022 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.screenshot + +import android.app.ActivityTaskManager.RootTaskInfo +import android.app.IActivityTaskManager +import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME +import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD +import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED +import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN +import android.app.WindowConfiguration.WINDOWING_MODE_PINNED +import android.content.ComponentName +import android.content.Context +import android.graphics.Rect +import android.os.UserHandle +import android.os.UserManager +import android.testing.AndroidTestingRunner +import com.android.systemui.SysuiTestCase +import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo +import com.android.systemui.util.mockito.mock +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking +import org.junit.Test +import org.junit.runner.RunWith + +// The following values are chosen to be distinct from commonly seen real values +private const val DISPLAY_ID = 100 +private const val PRIMARY_USER = 2000 +private const val MANAGED_PROFILE_USER = 3000 + +@RunWith(AndroidTestingRunner::class) +class ScreenshotPolicyImplTest : SysuiTestCase() { + + @Test + fun testToDisplayContentInfo() { + assertThat(fullScreenWorkProfileTask.toDisplayContentInfo()) + .isEqualTo( + DisplayContentInfo( + ComponentName( + "com.google.android.apps.nbu.files", + "com.google.android.apps.nbu.files.home.HomeActivity" + ), + Rect(0, 0, 1080, 2400), + UserHandle.of(MANAGED_PROFILE_USER), + 65)) + } + + @Test + fun findPrimaryContent_ignoresPipTask() = runBlocking { + val policy = fakeTasksPolicyImpl( + mContext, + shadeExpanded = false, + tasks = listOf( + pipTask, + fullScreenWorkProfileTask, + launcherTask, + emptyTask) + ) + + val info = policy.findPrimaryContent(DISPLAY_ID) + assertThat(info).isEqualTo(fullScreenWorkProfileTask.toDisplayContentInfo()) + } + + @Test + fun findPrimaryContent_shadeExpanded_ignoresTopTask() = runBlocking { + val policy = fakeTasksPolicyImpl( + mContext, + shadeExpanded = true, + tasks = listOf( + fullScreenWorkProfileTask, + launcherTask, + emptyTask) + ) + + val info = policy.findPrimaryContent(DISPLAY_ID) + assertThat(info).isEqualTo(policy.systemUiContent) + } + + @Test + fun findPrimaryContent_emptyTaskList() = runBlocking { + val policy = fakeTasksPolicyImpl( + mContext, + shadeExpanded = false, + tasks = listOf() + ) + + val info = policy.findPrimaryContent(DISPLAY_ID) + assertThat(info).isEqualTo(policy.systemUiContent) + } + + @Test + fun findPrimaryContent_workProfileNotOnTop() = runBlocking { + val policy = fakeTasksPolicyImpl( + mContext, + shadeExpanded = false, + tasks = listOf( + launcherTask, + fullScreenWorkProfileTask, + emptyTask) + ) + + val info = policy.findPrimaryContent(DISPLAY_ID) + assertThat(info).isEqualTo(launcherTask.toDisplayContentInfo()) + } + + private fun fakeTasksPolicyImpl( + context: Context, + shadeExpanded: Boolean, + tasks: List<RootTaskInfo> + ): ScreenshotPolicyImpl { + val userManager = mock<UserManager>() + val atmService = mock<IActivityTaskManager>() + val dispatcher = Dispatchers.Unconfined + + return object : ScreenshotPolicyImpl(context, userManager, atmService, dispatcher) { + override suspend fun isManagedProfile(userId: Int) = (userId == MANAGED_PROFILE_USER) + override suspend fun getAllRootTaskInfosOnDisplay(displayId: Int) = tasks + override suspend fun isNotificationShadeExpanded() = shadeExpanded + } + } + + private val pipTask = RootTaskInfo().apply { + configuration.windowConfiguration.apply { + windowingMode = WINDOWING_MODE_PINNED + bounds = Rect(628, 1885, 1038, 2295) + activityType = ACTIVITY_TYPE_STANDARD + } + displayId = DISPLAY_ID + userId = PRIMARY_USER + taskId = 66 + visible = true + isVisible = true + isRunning = true + numActivities = 1 + topActivity = ComponentName( + "com.google.android.youtube", + "com.google.android.apps.youtube.app.watchwhile.WatchWhileActivity" + ) + childTaskIds = intArrayOf(66) + childTaskNames = arrayOf("com.google.android.youtube/" + + "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity") + childTaskUserIds = intArrayOf(0) + childTaskBounds = arrayOf(Rect(628, 1885, 1038, 2295)) + } + + private val fullScreenWorkProfileTask = RootTaskInfo().apply { + configuration.windowConfiguration.apply { + windowingMode = WINDOWING_MODE_FULLSCREEN + bounds = Rect(0, 0, 1080, 2400) + activityType = ACTIVITY_TYPE_STANDARD + } + displayId = DISPLAY_ID + userId = MANAGED_PROFILE_USER + taskId = 65 + visible = true + isVisible = true + isRunning = true + numActivities = 1 + topActivity = ComponentName( + "com.google.android.apps.nbu.files", + "com.google.android.apps.nbu.files.home.HomeActivity" + ) + childTaskIds = intArrayOf(65) + childTaskNames = arrayOf("com.google.android.apps.nbu.files/" + + "com.google.android.apps.nbu.files.home.HomeActivity") + childTaskUserIds = intArrayOf(MANAGED_PROFILE_USER) + childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400)) + } + + private val launcherTask = RootTaskInfo().apply { + configuration.windowConfiguration.apply { + windowingMode = WINDOWING_MODE_FULLSCREEN + bounds = Rect(0, 0, 1080, 2400) + activityType = ACTIVITY_TYPE_HOME + } + displayId = DISPLAY_ID + taskId = 1 + userId = PRIMARY_USER + visible = true + isVisible = true + isRunning = true + numActivities = 1 + topActivity = ComponentName( + "com.google.android.apps.nexuslauncher", + "com.google.android.apps.nexuslauncher.NexusLauncherActivity", + ) + childTaskIds = intArrayOf(1) + childTaskNames = arrayOf("com.google.android.apps.nexuslauncher/" + + "com.google.android.apps.nexuslauncher.NexusLauncherActivity") + childTaskUserIds = intArrayOf(0) + childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400)) + } + + private val emptyTask = RootTaskInfo().apply { + configuration.windowConfiguration.apply { + windowingMode = WINDOWING_MODE_FULLSCREEN + bounds = Rect(0, 0, 1080, 2400) + activityType = ACTIVITY_TYPE_UNDEFINED + } + displayId = DISPLAY_ID + taskId = 2 + userId = PRIMARY_USER + visible = false + isVisible = false + isRunning = false + numActivities = 0 + childTaskIds = intArrayOf(3, 4) + childTaskNames = arrayOf("", "") + childTaskUserIds = intArrayOf(0, 0) + childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400), Rect(0, 2400, 1080, 4800)) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java index 98389c2c7a6f..e2ce939cb66c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java @@ -458,7 +458,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase { NotificationWakeUpCoordinator coordinator = new NotificationWakeUpCoordinator( - mDumpManager, mock(HeadsUpManagerPhone.class), new StatusBarStateControllerImpl(new UiEventLoggerFake(), mDumpManager, mInteractionJankMonitor), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java index a6b7e5103c78..ca98143044c1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java @@ -58,7 +58,6 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { @Before public void setup() { injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); - mDependency.injectMockDependency(DarkIconDispatcher.class); } @Test @@ -75,7 +74,8 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { layout, mock(FeatureFlags.class), mock(StatusBarPipelineFlags.class), - () -> mock(WifiViewModel.class)); + () -> mock(WifiViewModel.class), + mock(DarkIconDispatcher.class)); testCallOnAdd_forManager(manager); } @@ -116,8 +116,10 @@ public class StatusBarIconControllerTest extends LeakCheckedTest { LinearLayout group, FeatureFlags featureFlags, StatusBarPipelineFlags statusBarPipelineFlags, - Provider<WifiViewModel> wifiViewModelProvider) { - super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider); + Provider<WifiViewModel> wifiViewModelProvider, + DarkIconDispatcher darkIconDispatcher) { + super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider, + darkIconDispatcher); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt index 982927148a2e..d070ba0e47be 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt @@ -473,6 +473,40 @@ class WifiRepositoryImplTest : SysuiTestCase() { job.cancel() } + /** Regression test for b/244173280. */ + @Test + fun wifiNetwork_multipleSubscribers_newSubscribersGetCurrentValue() = runBlocking(IMMEDIATE) { + var latest1: WifiNetworkModel? = null + val job1 = underTest + .wifiNetwork + .onEach { latest1 = it } + .launchIn(this) + + getNetworkCallback() + .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)) + + assertThat(latest1 is WifiNetworkModel.Active).isTrue() + val latest1Active = latest1 as WifiNetworkModel.Active + assertThat(latest1Active.networkId).isEqualTo(NETWORK_ID) + assertThat(latest1Active.ssid).isEqualTo(SSID) + + // WHEN we add a second subscriber after having already emitted a value + var latest2: WifiNetworkModel? = null + val job2 = underTest + .wifiNetwork + .onEach { latest2 = it } + .launchIn(this) + + // THEN the second subscribe receives the already-emitted value + assertThat(latest2 is WifiNetworkModel.Active).isTrue() + val latest2Active = latest2 as WifiNetworkModel.Active + assertThat(latest2Active.networkId).isEqualTo(NETWORK_ID) + assertThat(latest2Active.ssid).isEqualTo(SSID) + + job1.cancel() + job2.cancel() + } + @Test fun wifiActivity_nullWifiManager_receivesDefault() = runBlocking(IMMEDIATE) { underTest = WifiRepositoryImpl( diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java index 312db2d7066a..2e74bf5474f9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -85,6 +85,8 @@ public class VolumeDialogImplTest extends SysuiTestCase { @Mock MediaOutputDialogFactory mMediaOutputDialogFactory; @Mock + VolumePanelFactory mVolumePanelFactory; + @Mock ActivityStarter mActivityStarter; @Mock InteractionJankMonitor mInteractionJankMonitor; @@ -102,6 +104,7 @@ public class VolumeDialogImplTest extends SysuiTestCase { mDeviceProvisionedController, mConfigurationController, mMediaOutputDialogFactory, + mVolumePanelFactory, mActivityStarter, mInteractionJankMonitor); mDialog.init(0, null); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt index b53ad0a3726f..c56fdb17b5f1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt @@ -16,14 +16,12 @@ package com.android.systemui.flags -import android.util.SparseArray -import android.util.SparseBooleanArray -import androidx.core.util.containsKey - class FakeFeatureFlags : FeatureFlags { - private val booleanFlags = SparseBooleanArray() - private val stringFlags = SparseArray<String>() + private val booleanFlags = mutableMapOf<Int, Boolean>() + private val stringFlags = mutableMapOf<Int, String>() private val knownFlagNames = mutableMapOf<Int, String>() + private val flagListeners = mutableMapOf<Int, MutableSet<FlagListenable.Listener>>() + private val listenerFlagIds = mutableMapOf<FlagListenable.Listener, MutableSet<Int>>() init { Flags.getFlagFields().forEach { field -> @@ -33,27 +31,52 @@ class FakeFeatureFlags : FeatureFlags { } fun set(flag: BooleanFlag, value: Boolean) { - booleanFlags.put(flag.id, value) + if (booleanFlags.put(flag.id, value)?.let { value != it } != false) { + notifyFlagChanged(flag) + } } fun set(flag: DeviceConfigBooleanFlag, value: Boolean) { - booleanFlags.put(flag.id, value) + if (booleanFlags.put(flag.id, value)?.let { value != it } != false) { + notifyFlagChanged(flag) + } } fun set(flag: ResourceBooleanFlag, value: Boolean) { - booleanFlags.put(flag.id, value) + if (booleanFlags.put(flag.id, value)?.let { value != it } != false) { + notifyFlagChanged(flag) + } } fun set(flag: SysPropBooleanFlag, value: Boolean) { - booleanFlags.put(flag.id, value) + if (booleanFlags.put(flag.id, value)?.let { value != it } != false) { + notifyFlagChanged(flag) + } } fun set(flag: StringFlag, value: String) { - stringFlags.put(flag.id, value) + if (stringFlags.put(flag.id, value)?.let { value != it } == null) { + notifyFlagChanged(flag) + } } fun set(flag: ResourceStringFlag, value: String) { - stringFlags.put(flag.id, value) + if (stringFlags.put(flag.id, value)?.let { value != it } == null) { + notifyFlagChanged(flag) + } + } + + private fun notifyFlagChanged(flag: Flag<*>) { + flagListeners[flag.id]?.let { listeners -> + listeners.forEach { listener -> + listener.onFlagChanged( + object : FlagListenable.FlagEvent { + override val flagId = flag.id + override fun requestNoRestart() {} + } + ) + } + } } override fun isEnabled(flag: UnreleasedFlag): Boolean = requireBooleanValue(flag.id) @@ -70,25 +93,30 @@ class FakeFeatureFlags : FeatureFlags { override fun getString(flag: ResourceStringFlag): String = requireStringValue(flag.id) - override fun addListener(flag: Flag<*>, listener: FlagListenable.Listener) {} + override fun addListener(flag: Flag<*>, listener: FlagListenable.Listener) { + flagListeners.getOrPut(flag.id) { mutableSetOf() }.add(listener) + listenerFlagIds.getOrPut(listener) { mutableSetOf() }.add(flag.id) + } - override fun removeListener(listener: FlagListenable.Listener) {} + override fun removeListener(listener: FlagListenable.Listener) { + listenerFlagIds.remove(listener)?.let { + flagIds -> flagIds.forEach { + id -> flagListeners[id]?.remove(listener) + } + } + } private fun flagName(flagId: Int): String { return knownFlagNames[flagId] ?: "UNKNOWN(id=$flagId)" } private fun requireBooleanValue(flagId: Int): Boolean { - if (!booleanFlags.containsKey(flagId)) { - throw IllegalStateException("Flag ${flagName(flagId)} was accessed but not specified.") - } return booleanFlags[flagId] + ?: error("Flag ${flagName(flagId)} was accessed but not specified.") } private fun requireStringValue(flagId: Int): String { - if (!stringFlags.containsKey(flagId)) { - throw IllegalStateException("Flag ${flagName(flagId)} was accessed but not specified.") - } return stringFlags[flagId] + ?: error("Flag ${flagName(flagId)} was accessed but not specified.") } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 6aa472fcd586..01af23da0f99 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -4248,7 +4248,8 @@ public final class ActiveServices { final String procName = r.processName; HostingRecord hostingRecord = new HostingRecord( HostingRecord.HOSTING_TYPE_SERVICE, r.instanceName, - r.definingPackageName, r.definingUid, r.serviceInfo.processName); + r.definingPackageName, r.definingUid, r.serviceInfo.processName, + getHostingRecordTriggerType(r)); ProcessRecord app; if (!isolated) { @@ -4358,6 +4359,14 @@ public final class ActiveServices { return null; } + private String getHostingRecordTriggerType(ServiceRecord r) { + if (Manifest.permission.BIND_JOB_SERVICE.equals(r.permission) + && r.mRecentCallingUid == SYSTEM_UID) { + return HostingRecord.TRIGGER_TYPE_JOB; + } + return HostingRecord.TRIGGER_TYPE_UNKNOWN; + } + private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg) throws TransactionTooLargeException { for (int i=r.bindings.size()-1; i>=0; i--) { diff --git a/services/core/java/com/android/server/am/HostingRecord.java b/services/core/java/com/android/server/am/HostingRecord.java index 2498f763ff77..30811a175bac 100644 --- a/services/core/java/com/android/server/am/HostingRecord.java +++ b/services/core/java/com/android/server/am/HostingRecord.java @@ -30,9 +30,10 @@ import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HO import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_SERVICE; import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_SYSTEM; import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_TOP_ACTIVITY; -import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_PUSH_MESSAGE; -import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_PUSH_MESSAGE_OVER_QUOTA; import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_ALARM; +import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_JOB; +import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_PUSH_MESSAGE; +import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_PUSH_MESSAGE_OVER_QUOTA; import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TYPE__UNKNOWN; @@ -97,6 +98,7 @@ public final class HostingRecord { public static final String TRIGGER_TYPE_ALARM = "alarm"; public static final String TRIGGER_TYPE_PUSH_MESSAGE = "push_message"; public static final String TRIGGER_TYPE_PUSH_MESSAGE_OVER_QUOTA = "push_message_over_quota"; + public static final String TRIGGER_TYPE_JOB = "job"; @NonNull private final String mHostingType; private final String mHostingName; @@ -126,10 +128,11 @@ public final class HostingRecord { } public HostingRecord(@NonNull String hostingType, ComponentName hostingName, - String definingPackageName, int definingUid, String definingProcessName) { + String definingPackageName, int definingUid, String definingProcessName, + String triggerType) { this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE, definingPackageName, definingUid, false /* isTopApp */, definingProcessName, null /* action */, - TRIGGER_TYPE_UNKNOWN); + triggerType); } public HostingRecord(@NonNull String hostingType, ComponentName hostingName, boolean isTopApp) { @@ -313,9 +316,11 @@ public final class HostingRecord { case TRIGGER_TYPE_ALARM: return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_ALARM; case TRIGGER_TYPE_PUSH_MESSAGE: - return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_PUSH_MESSAGE; + return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_PUSH_MESSAGE; case TRIGGER_TYPE_PUSH_MESSAGE_OVER_QUOTA: - return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_PUSH_MESSAGE_OVER_QUOTA; + return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_PUSH_MESSAGE_OVER_QUOTA; + case TRIGGER_TYPE_JOB: + return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_JOB; default: return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_UNKNOWN; } diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java index 66a4527bc2cb..4adbfaa79c69 100644 --- a/services/core/java/com/android/server/audio/BtHelper.java +++ b/services/core/java/com/android/server/audio/BtHelper.java @@ -53,8 +53,6 @@ public class BtHelper { private static final String TAG = "AS.BtHelper"; - private static final int SOURCE_CODEC_TYPE_OPUS = 6; // TODO remove in U - private final @NonNull AudioDeviceBroker mDeviceBroker; BtHelper(@NonNull AudioDeviceBroker broker) { @@ -913,7 +911,7 @@ public class BtHelper { return "ENCODING_APTX_HD"; case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC: return "ENCODING_LDAC"; - case SOURCE_CODEC_TYPE_OPUS: // TODO update in U + case BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS: return "ENCODING_OPUS"; default: return "ENCODING_BT_CODEC_TYPE(" + btCodecType + ")"; diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index 689ddd2fb9ee..c29755aaa845 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -72,7 +72,6 @@ import com.android.internal.os.SomeArgs; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.DumpUtils; import com.android.server.SystemService; -import com.android.server.biometrics.sensors.CoexCoordinator; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -951,16 +950,6 @@ public class BiometricService extends SystemService { return new ArrayList<>(); } - public boolean isAdvancedCoexLogicEnabled(Context context) { - return Settings.Secure.getInt(context.getContentResolver(), - CoexCoordinator.SETTING_ENABLE_NAME, 1) != 0; - } - - public boolean isCoexFaceNonBypassHapticsDisabled(Context context) { - return Settings.Secure.getInt(context.getContentResolver(), - CoexCoordinator.FACE_HAPTIC_DISABLE, 0) != 0; - } - public Supplier<Long> getRequestGenerator() { final AtomicLong generator = new AtomicLong(0); return () -> generator.incrementAndGet(); @@ -992,14 +981,6 @@ public class BiometricService extends SystemService { mEnabledOnKeyguardCallbacks); mRequestCounter = mInjector.getRequestGenerator(); - // TODO(b/193089985) This logic lives here (outside of CoexCoordinator) so that it doesn't - // need to depend on context. We can remove this code once the advanced logic is enabled - // by default. - CoexCoordinator coexCoordinator = CoexCoordinator.getInstance(); - coexCoordinator.setAdvancedLogicEnabled(injector.isAdvancedCoexLogicEnabled(context)); - coexCoordinator.setFaceHapticDisabledWhenNonBypass( - injector.isCoexFaceNonBypassHapticsDisabled(context)); - try { injector.getActivityManagerService().registerUserSwitchObserver( new UserSwitchObserver() { @@ -1333,7 +1314,5 @@ public class BiometricService extends SystemService { pw.println(); pw.println("CurrentSession: " + mAuthSession); pw.println(); - pw.println("CoexCoordinator: " + CoexCoordinator.getInstance().toString()); - pw.println(); } } diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java index 4eb6d38d9227..8a24ff6cffde 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java @@ -29,7 +29,6 @@ import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricOverlayConstants; import android.os.IBinder; import android.os.RemoteException; -import android.os.SystemClock; import android.security.KeyStore; import android.util.EventLog; import android.util.Slog; @@ -46,9 +45,7 @@ import java.util.function.Supplier; * A class to keep track of the authentication state for a given client. */ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> - implements AuthenticationConsumer { - - private static final String TAG = "Biometrics/AuthenticationClient"; + implements AuthenticationConsumer { // New, has not started yet public static final int STATE_NEW = 0; @@ -67,28 +64,27 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> STATE_STARTED_PAUSED_ATTEMPTED, STATE_STOPPED}) @interface State {} - + private static final String TAG = "Biometrics/AuthenticationClient"; + protected final long mOperationId; private final boolean mIsStrongBiometric; private final boolean mRequireConfirmation; private final ActivityTaskManager mActivityTaskManager; private final BiometricManager mBiometricManager; - @Nullable private final TaskStackListener mTaskStackListener; + @Nullable + private final TaskStackListener mTaskStackListener; private final LockoutTracker mLockoutTracker; private final boolean mIsRestricted; private final boolean mAllowBackgroundAuthentication; private final boolean mIsKeyguardBypassEnabled; - - protected final long mOperationId; - + // TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update + // the state. We should think of a way to improve this in the future. + @State + protected int mState = STATE_NEW; private long mStartTimeMs; private boolean mAuthAttempted; private boolean mAuthSuccess = false; - // TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update - // the state. We should think of a way to improve this in the future. - protected @State int mState = STATE_NEW; - public AuthenticationClient(@NonNull Context context, @NonNull Supplier<T> lazyDaemon, @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId, boolean restricted, @NonNull String owner, @@ -111,8 +107,9 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> mIsKeyguardBypassEnabled = isKeyguardBypassEnabled; } - public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) { - final @LockoutTracker.LockoutMode int lockoutMode = + @LockoutTracker.LockoutMode + public int handleFailedAttempt(int userId) { + @LockoutTracker.LockoutMode final int lockoutMode = mLockoutTracker.getLockoutModeForUser(userId); final PerformanceTracker performanceTracker = PerformanceTracker.getInstanceForSensorId(getSensorId()); @@ -173,14 +170,16 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> final ClientMonitorCallbackConverter listener = getListener(); - if (DEBUG) Slog.v(TAG, "onAuthenticated(" + authenticated + ")" - + ", ID:" + identifier.getBiometricId() - + ", Owner: " + getOwnerString() - + ", isBP: " + isBiometricPrompt() - + ", listener: " + listener - + ", requireConfirmation: " + mRequireConfirmation - + ", user: " + getTargetUserId() - + ", clientMonitor: " + toString()); + if (DEBUG) { + Slog.v(TAG, "onAuthenticated(" + authenticated + ")" + + ", ID:" + identifier.getBiometricId() + + ", Owner: " + getOwnerString() + + ", isBP: " + isBiometricPrompt() + + ", listener: " + listener + + ", requireConfirmation: " + mRequireConfirmation + + ", user: " + getTargetUserId() + + ", clientMonitor: " + this); + } final PerformanceTracker pm = PerformanceTracker.getInstanceForSensorId(getSensorId()); if (isCryptoOperation()) { @@ -239,142 +238,57 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> getSensorId(), getTargetUserId(), byteToken); } - final CoexCoordinator coordinator = CoexCoordinator.getInstance(); - coordinator.onAuthenticationSucceeded(SystemClock.uptimeMillis(), this, - new CoexCoordinator.Callback() { - @Override - public void sendAuthenticationResult(boolean addAuthTokenIfStrong) { - if (addAuthTokenIfStrong && mIsStrongBiometric) { - final int result = KeyStore.getInstance().addAuthToken(byteToken); - Slog.d(TAG, "addAuthToken: " + result); - } else { - Slog.d(TAG, "Skipping addAuthToken"); - } - - if (listener != null) { - try { - // Explicitly have if/else here to make it super obvious in case the - // code is touched in the future. - if (!mIsRestricted) { - listener.onAuthenticationSucceeded(getSensorId(), - identifier, - byteToken, - getTargetUserId(), - mIsStrongBiometric); - } else { - listener.onAuthenticationSucceeded(getSensorId(), - null /* identifier */, - byteToken, - getTargetUserId(), - mIsStrongBiometric); - } - } catch (RemoteException e) { - Slog.e(TAG, "Unable to notify listener", e); - } - } else { - Slog.w(TAG, "Client not listening"); - } + // For BP, BiometricService will add the authToken to Keystore. + if (!isBiometricPrompt() && mIsStrongBiometric) { + final int result = KeyStore.getInstance().addAuthToken(byteToken); + if (result != KeyStore.NO_ERROR) { + Slog.d(TAG, "Error adding auth token : " + result); + } else { + Slog.d(TAG, "addAuthToken: " + result); } - - @Override - public void sendHapticFeedback() { - if (listener != null && mShouldVibrate) { - vibrateSuccess(); + } else { + Slog.d(TAG, "Skipping addAuthToken"); + } + try { + if (listener != null) { + if (!mIsRestricted) { + listener.onAuthenticationSucceeded(getSensorId(), identifier, byteToken, + getTargetUserId(), mIsStrongBiometric); + } else { + listener.onAuthenticationSucceeded(getSensorId(), null /* identifier */, + byteToken, + getTargetUserId(), mIsStrongBiometric); } + } else { + Slog.e(TAG, "Received successful auth, but client was not listening"); } - - @Override - public void handleLifecycleAfterAuth() { - AuthenticationClient.this.handleLifecycleAfterAuth(true /* authenticated */); - } - - @Override - public void sendAuthenticationCanceled() { - sendCancelOnly(listener); - } - }); - } else { // not authenticated + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify listener", e); + mCallback.onClientFinished(this, false); + return; + } + } else { if (isBackgroundAuth) { Slog.e(TAG, "cancelling due to background auth"); cancel(); } else { // Allow system-defined limit of number of attempts before giving up - final @LockoutTracker.LockoutMode int lockoutMode = + @LockoutTracker.LockoutMode final int lockoutMode = handleFailedAttempt(getTargetUserId()); if (lockoutMode != LockoutTracker.LOCKOUT_NONE) { markAlreadyDone(); } - final CoexCoordinator coordinator = CoexCoordinator.getInstance(); - coordinator.onAuthenticationRejected(SystemClock.uptimeMillis(), this, lockoutMode, - new CoexCoordinator.Callback() { - @Override - public void sendAuthenticationResult(boolean addAuthTokenIfStrong) { - if (listener != null) { - try { - listener.onAuthenticationFailed(getSensorId()); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to notify listener", e); - } - } - } - - @Override - public void sendHapticFeedback() { - if (listener != null && mShouldVibrate) { - vibrateError(); - } - } - - @Override - public void handleLifecycleAfterAuth() { - AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */); - } - - @Override - public void sendAuthenticationCanceled() { - sendCancelOnly(listener); - } - }); - } - } - } - - /** - * Only call this method on interfaces where lockout does not come from onError, I.E. the - * old HIDL implementation. - */ - protected void onLockoutTimed(long durationMillis) { - final ClientMonitorCallbackConverter listener = getListener(); - final CoexCoordinator coordinator = CoexCoordinator.getInstance(); - coordinator.onAuthenticationError(this, BiometricConstants.BIOMETRIC_ERROR_LOCKOUT, - new CoexCoordinator.ErrorCallback() { - @Override - public void sendHapticFeedback() { - if (listener != null && mShouldVibrate) { - vibrateError(); - } - } - }); - } - - /** - * Only call this method on interfaces where lockout does not come from onError, I.E. the - * old HIDL implementation. - */ - protected void onLockoutPermanent() { - final ClientMonitorCallbackConverter listener = getListener(); - final CoexCoordinator coordinator = CoexCoordinator.getInstance(); - coordinator.onAuthenticationError(this, - BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT, - new CoexCoordinator.ErrorCallback() { - @Override - public void sendHapticFeedback() { - if (listener != null && mShouldVibrate) { - vibrateError(); + try { + listener.onAuthenticationFailed(getSensorId()); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to notify listener", e); + mCallback.onClientFinished(this, false); + return; } } - }); + } + AuthenticationClient.this.handleLifecycleAfterAuth(authenticated); } private void sendCancelOnly(@Nullable ClientMonitorCallbackConverter listener) { @@ -396,7 +310,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> public void onAcquired(int acquiredInfo, int vendorCode) { super.onAcquired(acquiredInfo, vendorCode); - final @LockoutTracker.LockoutMode int lockoutMode = + @LockoutTracker.LockoutMode final int lockoutMode = mLockoutTracker.getLockoutModeForUser(getTargetUserId()); if (lockoutMode == LockoutTracker.LOCKOUT_NONE) { PerformanceTracker pt = PerformanceTracker.getInstanceForSensorId(getSensorId()); @@ -408,8 +322,6 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> public void onError(@BiometricConstants.Errors int errorCode, int vendorCode) { super.onError(errorCode, vendorCode); mState = STATE_STOPPED; - - CoexCoordinator.getInstance().onAuthenticationError(this, errorCode, this::vibrateError); } /** @@ -419,7 +331,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> public void start(@NonNull ClientMonitorCallback callback) { super.start(callback); - final @LockoutTracker.LockoutMode int lockoutMode = + @LockoutTracker.LockoutMode final int lockoutMode = mLockoutTracker.getLockoutModeForUser(getTargetUserId()); if (lockoutMode != LockoutTracker.LOCKOUT_NONE) { Slog.v(TAG, "In lockout mode(" + lockoutMode + ") ; disallowing authentication"); @@ -450,22 +362,20 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> } /** - * Handles lifecycle, e.g. {@link BiometricScheduler}, - * {@link com.android.server.biometrics.sensors.BaseClientMonitor.Callback} after authentication - * results are known. Note that this happens asynchronously from (but shortly after) - * {@link #onAuthenticated(BiometricAuthenticator.Identifier, boolean, ArrayList)} and allows - * {@link CoexCoordinator} a chance to invoke/delay this event. - * @param authenticated + * Handles lifecycle, e.g. {@link BiometricScheduler} after authentication. This is necessary + * as different clients handle the lifecycle of authentication success/reject differently. I.E. + * Fingerprint does not finish authentication when it is rejected. */ protected abstract void handleLifecycleAfterAuth(boolean authenticated); /** * @return true if a user was detected (i.e. face was found, fingerprint sensor was touched. - * etc) + * etc) */ public abstract boolean wasUserDetected(); - public @State int getState() { + @State + public int getState() { return mState; } diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java index 63609f77dc75..9317c4ec12b5 100644 --- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java +++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java @@ -54,7 +54,7 @@ import java.util.function.Consumer; * interactions with the HAL before finishing. * * We currently assume (and require) that each biometric sensor have its own instance of a - * {@link BiometricScheduler}. See {@link CoexCoordinator}. + * {@link BiometricScheduler}. */ @MainThread public class BiometricScheduler { @@ -156,7 +156,6 @@ public class BiometricScheduler { private int mTotalOperationsHandled; private final int mRecentOperationsLimit; @NonNull private final List<Integer> mRecentOperations; - @NonNull private final CoexCoordinator mCoexCoordinator; // Internal callback, notified when an operation is complete. Notifies the requester // that the operation is complete, before performing internal scheduler work (such as @@ -165,11 +164,6 @@ public class BiometricScheduler { @Override public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { Slog.d(getTag(), "[Started] " + clientMonitor); - - if (clientMonitor instanceof AuthenticationClient) { - mCoexCoordinator.addAuthenticationClient(mSensorType, - (AuthenticationClient<?>) clientMonitor); - } } @Override @@ -189,10 +183,6 @@ public class BiometricScheduler { } Slog.d(getTag(), "[Finishing] " + clientMonitor + ", success: " + success); - if (clientMonitor instanceof AuthenticationClient) { - mCoexCoordinator.removeAuthenticationClient(mSensorType, - (AuthenticationClient<?>) clientMonitor); - } if (mGestureAvailabilityDispatcher != null) { mGestureAvailabilityDispatcher.markSensorActive( @@ -216,8 +206,7 @@ public class BiometricScheduler { @SensorType int sensorType, @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher, @NonNull IBiometricService biometricService, - int recentOperationsLimit, - @NonNull CoexCoordinator coexCoordinator) { + int recentOperationsLimit) { mBiometricTag = tag; mHandler = handler; mSensorType = sensorType; @@ -227,7 +216,6 @@ public class BiometricScheduler { mCrashStates = new ArrayDeque<>(); mRecentOperationsLimit = recentOperationsLimit; mRecentOperations = new ArrayList<>(); - mCoexCoordinator = coexCoordinator; } /** @@ -244,7 +232,7 @@ public class BiometricScheduler { this(tag, new Handler(Looper.getMainLooper()), sensorType, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface( ServiceManager.getService(Context.BIOMETRIC_SERVICE)), - LOG_NUM_RECENT_OPERATIONS, CoexCoordinator.getInstance()); + LOG_NUM_RECENT_OPERATIONS); } @VisibleForTesting diff --git a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java deleted file mode 100644 index c8a90e7a564b..000000000000 --- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java +++ /dev/null @@ -1,525 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.biometrics.sensors; - -import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FACE; -import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_UDFPS; -import static com.android.server.biometrics.sensors.BiometricScheduler.sensorTypeToString; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.hardware.biometrics.BiometricConstants; -import android.os.Handler; -import android.os.Looper; -import android.util.Slog; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.server.biometrics.sensors.BiometricScheduler.SensorType; -import com.android.server.biometrics.sensors.fingerprint.Udfps; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; - -/** - * Singleton that contains the core logic for determining if haptics and authentication callbacks - * should be sent to receivers. Note that this class is used even when coex is not required (e.g. - * single sensor devices, or multi-sensor devices where only a single sensor is authenticating). - * This allows us to have all business logic in one testable place. - */ -public class CoexCoordinator { - - private static final String TAG = "BiometricCoexCoordinator"; - public static final String SETTING_ENABLE_NAME = - "com.android.server.biometrics.sensors.CoexCoordinator.enable"; - public static final String FACE_HAPTIC_DISABLE = - "com.android.server.biometrics.sensors.CoexCoordinator.disable_face_haptics"; - private static final boolean DEBUG = true; - - // Successful authentications should be used within this amount of time. - static final long SUCCESSFUL_AUTH_VALID_DURATION_MS = 5000; - - /** - * Callback interface notifying the owner of "results" from the CoexCoordinator's business - * logic for accept and reject. - */ - interface Callback { - /** - * Requests the owner to send the result (success/reject) and any associated info to the - * receiver (e.g. keyguard, BiometricService, etc). - */ - void sendAuthenticationResult(boolean addAuthTokenIfStrong); - - /** - * Requests the owner to initiate a vibration for this event. - */ - void sendHapticFeedback(); - - /** - * Requests the owner to handle the AuthenticationClient's lifecycle (e.g. finish and remove - * from scheduler if auth was successful). - */ - void handleLifecycleAfterAuth(); - - /** - * Requests the owner to notify the caller that authentication was canceled. - */ - void sendAuthenticationCanceled(); - } - - /** - * Callback interface notifying the owner of "results" from the CoexCoordinator's business - * logic for errors. - */ - interface ErrorCallback { - /** - * Requests the owner to initiate a vibration for this event. - */ - void sendHapticFeedback(); - } - - private static final CoexCoordinator sInstance = new CoexCoordinator(); - - @VisibleForTesting - public static class SuccessfulAuth { - final long mAuthTimestamp; - final @SensorType int mSensorType; - final AuthenticationClient<?> mAuthenticationClient; - final Callback mCallback; - final CleanupRunnable mCleanupRunnable; - - public static class CleanupRunnable implements Runnable { - @NonNull final LinkedList<SuccessfulAuth> mSuccessfulAuths; - @NonNull final SuccessfulAuth mAuth; - @NonNull final Callback mCallback; - - public CleanupRunnable(@NonNull LinkedList<SuccessfulAuth> successfulAuths, - @NonNull SuccessfulAuth auth, @NonNull Callback callback) { - mSuccessfulAuths = successfulAuths; - mAuth = auth; - mCallback = callback; - } - - @Override - public void run() { - final boolean removed = mSuccessfulAuths.remove(mAuth); - Slog.w(TAG, "Removing stale successfulAuth: " + mAuth.toString() - + ", success: " + removed); - mCallback.handleLifecycleAfterAuth(); - } - } - - public SuccessfulAuth(@NonNull Handler handler, - @NonNull LinkedList<SuccessfulAuth> successfulAuths, - long currentTimeMillis, - @SensorType int sensorType, - @NonNull AuthenticationClient<?> authenticationClient, - @NonNull Callback callback) { - mAuthTimestamp = currentTimeMillis; - mSensorType = sensorType; - mAuthenticationClient = authenticationClient; - mCallback = callback; - - mCleanupRunnable = new CleanupRunnable(successfulAuths, this, callback); - - handler.postDelayed(mCleanupRunnable, SUCCESSFUL_AUTH_VALID_DURATION_MS); - } - - @Override - public String toString() { - return "SensorType: " + sensorTypeToString(mSensorType) - + ", mAuthTimestamp: " + mAuthTimestamp - + ", authenticationClient: " + mAuthenticationClient; - } - } - - /** The singleton instance. */ - @NonNull - public static CoexCoordinator getInstance() { - return sInstance; - } - - @VisibleForTesting - public void setAdvancedLogicEnabled(boolean enabled) { - mAdvancedLogicEnabled = enabled; - } - - public void setFaceHapticDisabledWhenNonBypass(boolean disabled) { - mFaceHapticDisabledWhenNonBypass = disabled; - } - - @VisibleForTesting - void reset() { - mClientMap.clear(); - } - - // SensorType to AuthenticationClient map - private final Map<Integer, AuthenticationClient<?>> mClientMap = new HashMap<>(); - @VisibleForTesting final LinkedList<SuccessfulAuth> mSuccessfulAuths = new LinkedList<>(); - private boolean mAdvancedLogicEnabled; - private boolean mFaceHapticDisabledWhenNonBypass; - private final Handler mHandler = new Handler(Looper.getMainLooper()); - - private CoexCoordinator() {} - - public void addAuthenticationClient(@BiometricScheduler.SensorType int sensorType, - @NonNull AuthenticationClient<?> client) { - if (DEBUG) { - Slog.d(TAG, "addAuthenticationClient(" + sensorTypeToString(sensorType) + ")" - + ", client: " + client); - } - - if (mClientMap.containsKey(sensorType)) { - Slog.w(TAG, "Overwriting existing client: " + mClientMap.get(sensorType) - + " with new client: " + client); - } - - mClientMap.put(sensorType, client); - } - - public void removeAuthenticationClient(@BiometricScheduler.SensorType int sensorType, - @NonNull AuthenticationClient<?> client) { - if (DEBUG) { - Slog.d(TAG, "removeAuthenticationClient(" + sensorTypeToString(sensorType) + ")" - + ", client: " + client); - } - - if (!mClientMap.containsKey(sensorType)) { - Slog.e(TAG, "sensorType: " + sensorType + " does not exist in map. Client: " + client); - return; - } - mClientMap.remove(sensorType); - } - - /** - * Notify the coordinator that authentication succeeded (accepted) - */ - public void onAuthenticationSucceeded(long currentTimeMillis, - @NonNull AuthenticationClient<?> client, - @NonNull Callback callback) { - final boolean isUsingSingleModality = isSingleAuthOnly(client); - - if (client.isBiometricPrompt()) { - if (!isUsingSingleModality && hasMultipleSuccessfulAuthentications()) { - // only send feedback on the first one - } else { - callback.sendHapticFeedback(); - } - // For BP, BiometricService will add the authToken to Keystore. - callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */); - callback.handleLifecycleAfterAuth(); - } else if (isUnknownClient(client)) { - // Client doesn't exist in our map for some reason. Give the user feedback so the - // device doesn't feel like it's stuck. All other cases below can assume that the - // client exists in our map. - callback.sendHapticFeedback(); - callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); - callback.handleLifecycleAfterAuth(); - } else if (mAdvancedLogicEnabled && client.isKeyguard()) { - if (isUsingSingleModality) { - // Single sensor authentication - callback.sendHapticFeedback(); - callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); - callback.handleLifecycleAfterAuth(); - } else { - // Multi sensor authentication - AuthenticationClient<?> udfps = mClientMap.getOrDefault(SENSOR_TYPE_UDFPS, null); - AuthenticationClient<?> face = mClientMap.getOrDefault(SENSOR_TYPE_FACE, null); - if (isCurrentFaceAuth(client)) { - if (isUdfpsActivelyAuthing(udfps)) { - // Face auth success while UDFPS is actively authing. No callback, no haptic - // Feedback will be provided after UDFPS result: - // 1) UDFPS succeeds - simply remove this from the queue - // 2) UDFPS rejected - use this face auth success to notify clients - mSuccessfulAuths.add(new SuccessfulAuth(mHandler, mSuccessfulAuths, - currentTimeMillis, SENSOR_TYPE_FACE, client, callback)); - } else { - if (mFaceHapticDisabledWhenNonBypass && !face.isKeyguardBypassEnabled()) { - Slog.w(TAG, "Skipping face success haptic"); - } else { - callback.sendHapticFeedback(); - } - callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); - callback.handleLifecycleAfterAuth(); - } - } else if (isCurrentUdfps(client)) { - if (isFaceScanning()) { - // UDFPS succeeds while face is still scanning - // Cancel face auth and/or prevent it from invoking haptics/callbacks after - face.cancel(); - } - - removeAndFinishAllFaceFromQueue(); - - callback.sendHapticFeedback(); - callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); - callback.handleLifecycleAfterAuth(); - } else { - // Capacitive fingerprint sensor (or other) - callback.sendHapticFeedback(); - callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); - callback.handleLifecycleAfterAuth(); - } - } - } else { - // Non-keyguard authentication. For example, Fingerprint Settings use of - // FingerprintManager for highlighting fingers - callback.sendHapticFeedback(); - callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); - callback.handleLifecycleAfterAuth(); - } - } - - /** - * Notify the coordinator that a rejection has occurred. - */ - public void onAuthenticationRejected(long currentTimeMillis, - @NonNull AuthenticationClient<?> client, - @LockoutTracker.LockoutMode int lockoutMode, - @NonNull Callback callback) { - final boolean isUsingSingleModality = isSingleAuthOnly(client); - - if (mAdvancedLogicEnabled && client.isKeyguard()) { - if (isUsingSingleModality) { - callback.sendHapticFeedback(); - callback.handleLifecycleAfterAuth(); - } else { - // Multi sensor authentication - AuthenticationClient<?> udfps = mClientMap.getOrDefault(SENSOR_TYPE_UDFPS, null); - AuthenticationClient<?> face = mClientMap.getOrDefault(SENSOR_TYPE_FACE, null); - if (isCurrentFaceAuth(client)) { - if (isUdfpsActivelyAuthing(udfps)) { - // UDFPS should still be running in this case, do not vibrate. However, we - // should notify the callback and finish the client, so that Keyguard and - // BiometricScheduler do not get stuck. - Slog.d(TAG, "Face rejected in multi-sensor auth, udfps: " + udfps); - callback.handleLifecycleAfterAuth(); - } else if (isUdfpsAuthAttempted(udfps)) { - // If UDFPS is STATE_STARTED_PAUSED (e.g. finger rejected but can still - // auth after pointer goes down, it means UDFPS encountered a rejection. In - // this case, we need to play the final reject haptic since face auth is - // also done now. - callback.sendHapticFeedback(); - callback.handleLifecycleAfterAuth(); - } else { - // UDFPS auth has never been attempted. - if (mFaceHapticDisabledWhenNonBypass && !face.isKeyguardBypassEnabled()) { - Slog.w(TAG, "Skipping face reject haptic"); - } else { - callback.sendHapticFeedback(); - } - callback.handleLifecycleAfterAuth(); - } - } else if (isCurrentUdfps(client)) { - // Face should either be running, or have already finished - SuccessfulAuth auth = popSuccessfulFaceAuthIfExists(currentTimeMillis); - if (auth != null) { - Slog.d(TAG, "Using recent auth: " + auth); - callback.handleLifecycleAfterAuth(); - - auth.mCallback.sendHapticFeedback(); - auth.mCallback.sendAuthenticationResult(true /* addAuthTokenIfStrong */); - auth.mCallback.handleLifecycleAfterAuth(); - } else { - Slog.d(TAG, "UDFPS rejected in multi-sensor auth"); - callback.sendHapticFeedback(); - callback.handleLifecycleAfterAuth(); - } - } else { - Slog.d(TAG, "Unknown client rejected: " + client); - callback.sendHapticFeedback(); - callback.handleLifecycleAfterAuth(); - } - } - } else if (client.isBiometricPrompt() && !isUsingSingleModality) { - if (!isCurrentFaceAuth(client)) { - callback.sendHapticFeedback(); - } - callback.handleLifecycleAfterAuth(); - } else { - callback.sendHapticFeedback(); - callback.handleLifecycleAfterAuth(); - } - - // Always notify keyguard, otherwise the cached "running" state in KeyguardUpdateMonitor - // will get stuck. - if (lockoutMode == LockoutTracker.LOCKOUT_NONE) { - // Don't send onAuthenticationFailed if we're in lockout, it causes a - // janky UI on Keyguard/BiometricPrompt since "authentication failed" - // will show briefly and be replaced by "device locked out" message. - callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */); - } - } - - /** - * Notify the coordinator that an error has occurred. - */ - public void onAuthenticationError(@NonNull AuthenticationClient<?> client, - @BiometricConstants.Errors int error, @NonNull ErrorCallback callback) { - final boolean isUsingSingleModality = isSingleAuthOnly(client); - - // Figure out non-coex state - final boolean shouldUsuallyVibrate; - if (isCurrentFaceAuth(client)) { - final boolean notDetectedOnKeyguard = client.isKeyguard() && !client.wasUserDetected(); - final boolean authAttempted = client.wasAuthAttempted(); - - switch (error) { - case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT: - case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT: - case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT: - shouldUsuallyVibrate = authAttempted && !notDetectedOnKeyguard; - break; - default: - shouldUsuallyVibrate = false; - break; - } - } else { - shouldUsuallyVibrate = false; - } - - // Figure out coex state - final boolean hapticSuppressedByCoex; - if (mAdvancedLogicEnabled && client.isKeyguard()) { - if (isUsingSingleModality) { - hapticSuppressedByCoex = false; - } else { - hapticSuppressedByCoex = isCurrentFaceAuth(client) - && !client.isKeyguardBypassEnabled(); - } - } else if (client.isBiometricPrompt() && !isUsingSingleModality) { - hapticSuppressedByCoex = isCurrentFaceAuth(client); - } else { - hapticSuppressedByCoex = false; - } - - // Combine and send feedback if appropriate - if (shouldUsuallyVibrate && !hapticSuppressedByCoex) { - callback.sendHapticFeedback(); - } else { - Slog.v(TAG, "no haptic shouldUsuallyVibrate: " + shouldUsuallyVibrate - + ", hapticSuppressedByCoex: " + hapticSuppressedByCoex); - } - } - - @Nullable - private SuccessfulAuth popSuccessfulFaceAuthIfExists(long currentTimeMillis) { - for (SuccessfulAuth auth : mSuccessfulAuths) { - if (currentTimeMillis - auth.mAuthTimestamp >= SUCCESSFUL_AUTH_VALID_DURATION_MS) { - // TODO(b/193089985): This removes the auth but does not notify the client with - // an appropriate lifecycle event (such as ERROR_CANCELED), and violates the - // API contract. However, this might be OK for now since the validity duration - // is way longer than the time it takes to auth with fingerprint. - Slog.e(TAG, "Removing stale auth: " + auth); - mSuccessfulAuths.remove(auth); - } else if (auth.mSensorType == SENSOR_TYPE_FACE) { - mSuccessfulAuths.remove(auth); - return auth; - } - } - return null; - } - - private void removeAndFinishAllFaceFromQueue() { - // Note that these auth are all successful, but have never notified the client (e.g. - // keyguard). To comply with the authentication lifecycle, we must notify the client that - // auth is "done". The safest thing to do is to send ERROR_CANCELED. - for (SuccessfulAuth auth : mSuccessfulAuths) { - if (auth.mSensorType == SENSOR_TYPE_FACE) { - Slog.d(TAG, "Removing from queue, canceling, and finishing: " + auth); - auth.mCallback.sendAuthenticationCanceled(); - auth.mCallback.handleLifecycleAfterAuth(); - mSuccessfulAuths.remove(auth); - } - } - } - - private boolean isCurrentFaceAuth(@NonNull AuthenticationClient<?> client) { - return client == mClientMap.getOrDefault(SENSOR_TYPE_FACE, null); - } - - private boolean isCurrentUdfps(@NonNull AuthenticationClient<?> client) { - return client == mClientMap.getOrDefault(SENSOR_TYPE_UDFPS, null); - } - - private boolean isFaceScanning() { - AuthenticationClient<?> client = mClientMap.getOrDefault(SENSOR_TYPE_FACE, null); - return client != null && client.getState() == AuthenticationClient.STATE_STARTED; - } - - private static boolean isUdfpsActivelyAuthing(@Nullable AuthenticationClient<?> client) { - if (client instanceof Udfps) { - return client.getState() == AuthenticationClient.STATE_STARTED; - } - return false; - } - - private static boolean isUdfpsAuthAttempted(@Nullable AuthenticationClient<?> client) { - if (client instanceof Udfps) { - return client.getState() == AuthenticationClient.STATE_STARTED_PAUSED_ATTEMPTED; - } - return false; - } - - private boolean isUnknownClient(@NonNull AuthenticationClient<?> client) { - for (AuthenticationClient<?> c : mClientMap.values()) { - if (c == client) { - return false; - } - } - return true; - } - - private boolean isSingleAuthOnly(@NonNull AuthenticationClient<?> client) { - if (mClientMap.values().size() != 1) { - return false; - } - - for (AuthenticationClient<?> c : mClientMap.values()) { - if (c != client) { - return false; - } - } - return true; - } - - private boolean hasMultipleSuccessfulAuthentications() { - int count = 0; - for (AuthenticationClient<?> c : mClientMap.values()) { - if (c.wasAuthSuccessful()) { - count++; - } - if (count > 1) { - return true; - } - } - return false; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("Enabled: ").append(mAdvancedLogicEnabled); - sb.append(", Face Haptic Disabled: ").append(mFaceHapticDisabledWhenNonBypass); - sb.append(", Queue size: " ).append(mSuccessfulAuths.size()); - for (SuccessfulAuth auth : mSuccessfulAuths) { - sb.append(", Auth: ").append(auth.toString()); - } - - return sb.toString(); - } -} diff --git a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java index ae75b7dcc101..a486d16189fa 100644 --- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java +++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java @@ -95,10 +95,9 @@ public class UserAwareBiometricScheduler extends BiometricScheduler { @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher, @NonNull IBiometricService biometricService, @NonNull CurrentUserRetriever currentUserRetriever, - @NonNull UserSwitchCallback userSwitchCallback, - @NonNull CoexCoordinator coexCoordinator) { + @NonNull UserSwitchCallback userSwitchCallback) { super(tag, handler, sensorType, gestureAvailabilityDispatcher, biometricService, - LOG_NUM_RECENT_OPERATIONS, coexCoordinator); + LOG_NUM_RECENT_OPERATIONS); mCurrentUserRetriever = currentUserRetriever; mUserSwitchCallback = userSwitchCallback; @@ -112,7 +111,7 @@ public class UserAwareBiometricScheduler extends BiometricScheduler { this(tag, new Handler(Looper.getMainLooper()), sensorType, gestureAvailabilityDispatcher, IBiometricService.Stub.asInterface( ServiceManager.getService(Context.BIOMETRIC_SERVICE)), - currentUserRetriever, userSwitchCallback, CoexCoordinator.getInstance()); + currentUserRetriever, userSwitchCallback); } @Override diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java index ca4b7475f7dc..e18e31ec33ea 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java @@ -274,7 +274,6 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession> @Override public void onLockoutTimed(long durationMillis) { - super.onLockoutTimed(durationMillis); mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED); // Lockout metrics are logged as an error code. final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT; @@ -290,7 +289,6 @@ class FaceAuthenticationClient extends AuthenticationClient<AidlSession> @Override public void onLockoutPermanent() { - super.onLockoutPermanent(); mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT); // Lockout metrics are logged as an error code. final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT; 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 1688f966eccd..f2c5b970d52c 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 @@ -424,7 +424,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession> @Override public void onLockoutTimed(long durationMillis) { - super.onLockoutTimed(durationMillis); mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED); // Lockout metrics are logged as an error code. final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT; @@ -448,7 +447,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<AidlSession> @Override public void onLockoutPermanent() { - super.onLockoutPermanent(); mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT); // Lockout metrics are logged as an error code. final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT; diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index 25d0752844fd..c835d2fe1bbd 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -116,8 +116,10 @@ public abstract class BrightnessMappingStrategy { luxLevels = getLuxLevels(resources.getIntArray( com.android.internal.R.array.config_autoBrightnessLevelsIdle)); } else { - brightnessLevelsNits = displayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(); - luxLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(); + brightnessLevelsNits = getFloatArray(resources.obtainTypedArray( + com.android.internal.R.array.config_autoBrightnessDisplayValuesNits)); + luxLevels = getLuxLevels(resources.getIntArray( + com.android.internal.R.array.config_autoBrightnessLevels)); } // Display independent, mode independent values diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java index 3b627ef6a786..4f3fd6409cd8 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java +++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java @@ -20,7 +20,6 @@ import android.annotation.NonNull; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; -import android.content.res.TypedArray; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; import android.os.Environment; @@ -150,22 +149,12 @@ import javax.xml.datatype.DatatypeConfigurationException; * </quirks> * * <autoBrightness> - * <brighteningLightDebounceMillis> + * <brighteningLightDebounceMillis> * 2000 - * </brighteningLightDebounceMillis> + * </brighteningLightDebounceMillis> * <darkeningLightDebounceMillis> * 1000 * </darkeningLightDebounceMillis> - * <displayBrightnessMapping> - * <displayBrightnessPoint> - * <lux>50</lux> - * <nits>45</nits> - * </displayBrightnessPoint> - * <displayBrightnessPoint> - * <lux>80</lux> - * <nits>75</nits> - * </displayBrightnessPoint> - * </displayBrightnessMapping> * </autoBrightness> * * <screenBrightnessRampFastDecrease>0.01</screenBrightnessRampFastDecrease> @@ -279,39 +268,6 @@ public class DisplayDeviceConfig { // for the corresponding values above private float[] mBrightness; - - /** - * Array of desired screen brightness in nits corresponding to the lux values - * in the mBrightnessLevelsLux array. The display brightness is defined as the - * measured brightness of an all-white image. The brightness values must be non-negative and - * non-decreasing. This must be overridden in platform specific overlays - */ - private float[] mBrightnessLevelsNits; - - /** - * Array of light sensor lux values to define our levels for auto backlight - * brightness support. - * The N entries of this array define N + 1 control points as follows: - * (1-based arrays) - * - * Point 1: (0, value[1]): lux <= 0 - * Point 2: (level[1], value[2]): 0 < lux <= level[1] - * Point 3: (level[2], value[3]): level[2] < lux <= level[3] - * ... - * Point N+1: (level[N], value[N+1]): level[N] < lux - * - * The control points must be strictly increasing. Each control point - * corresponds to an entry in the brightness backlight values arrays. - * For example, if lux == level[1] (first element of the levels array) - * then the brightness will be determined by value[2] (second element - * of the brightness values array). - * - * Spline interpolation is used to determine the auto-brightness - * backlight values for lux levels between these control points. - * - */ - private float[] mBrightnessLevelsLux; - private float mBacklightMinimum = Float.NaN; private float mBacklightMaximum = Float.NaN; private float mBrightnessDefault = Float.NaN; @@ -705,20 +661,6 @@ public class DisplayDeviceConfig { return mAutoBrightnessBrighteningLightDebounce; } - /** - * @return Auto brightness brightening ambient lux levels - */ - public float[] getAutoBrightnessBrighteningLevelsLux() { - return mBrightnessLevelsLux; - } - - /** - * @return Auto brightness brightening nits levels - */ - public float[] getAutoBrightnessBrighteningLevelsNits() { - return mBrightnessLevelsNits; - } - @Override public String toString() { return "DisplayDeviceConfig{" @@ -761,8 +703,6 @@ public class DisplayDeviceConfig { + mAutoBrightnessBrighteningLightDebounce + ", mAutoBrightnessDarkeningLightDebounce= " + mAutoBrightnessDarkeningLightDebounce - + ", mBrightnessLevelsLux= " + Arrays.toString(mBrightnessLevelsLux) - + ", mBrightnessLevelsNits= " + Arrays.toString(mBrightnessLevelsNits) + "}"; } @@ -839,7 +779,6 @@ public class DisplayDeviceConfig { loadBrightnessRampsFromConfigXml(); loadAmbientLightSensorFromConfigXml(); setProxSensorUnspecified(); - loadAutoBrightnessConfigsFromConfigXml(); mLoadedFrom = "<config.xml>"; } @@ -1052,7 +991,6 @@ public class DisplayDeviceConfig { private void loadAutoBrightnessConfigValues(DisplayConfiguration config) { loadAutoBrightnessBrighteningLightDebounce(config.getAutoBrightness()); loadAutoBrightnessDarkeningLightDebounce(config.getAutoBrightness()); - loadAutoBrightnessDisplayBrightnessMapping(config.getAutoBrightness()); } /** @@ -1085,33 +1023,6 @@ public class DisplayDeviceConfig { } } - /** - * Loads the auto-brightness display brightness mappings. Internally, this takes care of - * loading the value from the display config, and if not present, falls back to config.xml. - */ - private void loadAutoBrightnessDisplayBrightnessMapping(AutoBrightness autoBrightnessConfig) { - if (autoBrightnessConfig == null - || autoBrightnessConfig.getDisplayBrightnessMapping() == null) { - mBrightnessLevelsNits = getFloatArray(mContext.getResources() - .obtainTypedArray(com.android.internal.R.array - .config_autoBrightnessDisplayValuesNits)); - mBrightnessLevelsLux = getFloatArray(mContext.getResources() - .obtainTypedArray(com.android.internal.R.array - .config_autoBrightnessLevels)); - } else { - final int size = autoBrightnessConfig.getDisplayBrightnessMapping() - .getDisplayBrightnessPoint().size(); - mBrightnessLevelsNits = new float[size]; - mBrightnessLevelsLux = new float[size]; - for (int i = 0; i < size; i++) { - mBrightnessLevelsNits[i] = autoBrightnessConfig.getDisplayBrightnessMapping() - .getDisplayBrightnessPoint().get(i).getNits().floatValue(); - mBrightnessLevelsLux[i] = autoBrightnessConfig.getDisplayBrightnessMapping() - .getDisplayBrightnessPoint().get(i).getLux().floatValue(); - } - } - } - private void loadBrightnessMapFromConfigXml() { // Use the config.xml mapping final Resources res = mContext.getResources(); @@ -1337,10 +1248,6 @@ public class DisplayDeviceConfig { com.android.internal.R.string.config_displayLightSensorType); } - private void loadAutoBrightnessConfigsFromConfigXml() { - loadAutoBrightnessDisplayBrightnessMapping(null /*AutoBrightnessConfig*/); - } - private void loadAmbientLightSensorFromDdc(DisplayConfiguration config) { final SensorDetails sensorDetails = config.getLightSensor(); if (sensorDetails != null) { @@ -1483,22 +1390,6 @@ public class DisplayDeviceConfig { } } - /** - * Extracts a float array from the specified {@link TypedArray}. - * - * @param array The array to convert. - * @return the given array as a float array. - */ - public static float[] getFloatArray(TypedArray array) { - final int n = array.length(); - float[] vals = new float[n]; - for (int i = 0; i < n; i++) { - vals[i] = array.getFloat(i, PowerManager.BRIGHTNESS_OFF_FLOAT); - } - array.recycle(); - return vals; - } - static class SensorData { public String type; public String name; diff --git a/services/core/java/com/android/server/logcat/OWNERS b/services/core/java/com/android/server/logcat/OWNERS index 9588fa9d1f8e..87d30f3dd537 100644 --- a/services/core/java/com/android/server/logcat/OWNERS +++ b/services/core/java/com/android/server/logcat/OWNERS @@ -1,5 +1,7 @@ cbrubaker@google.com eunjeongshin@google.com +georgechan@google.com jsharkey@google.com vishwath@google.com wenhaowang@google.com +xiaozhenl@google.com diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java index c12dc8e9e92e..a5c762a1df0b 100644 --- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java +++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java @@ -119,7 +119,7 @@ final class MediaButtonReceiverHolder { ComponentName componentName = getComponentName(pendingIntent, componentType); if (componentName != null) { if (!TextUtils.equals(componentName.getPackageName(), sessionPackageName)) { - EventLog.writeEvent(0x534e4554, "238177121", -1, ""); // SafetyNet Logging. + EventLog.writeEvent(0x534e4554, "238177121", -1, ""); throw new IllegalArgumentException("ComponentName does not belong to " + "sessionPackageName. sessionPackageName = " + sessionPackageName + ", ComponentName pkg = " + componentName.getPackageName()); diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 4f8771a3ddef..1ee9a873fff9 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -914,7 +914,16 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR } @Override - public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException { + public void setMediaButtonReceiver(PendingIntent pi, String sessionPackageName) + throws RemoteException { + //mPackageName has been verified in MediaSessionService.enforcePackageName(). + if (!TextUtils.equals(sessionPackageName, mPackageName)) { + EventLog.writeEvent(0x534e4554, "238177121", -1, ""); + throw new IllegalArgumentException("sessionPackageName name does not match " + + "package name provided to MediaSessionRecord. sessionPackageName = " + + sessionPackageName + ", pkg = " + + mPackageName); + } final long token = Binder.clearCallingIdentity(); try { if ((mPolicies & MediaSessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER) @@ -922,7 +931,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR return; } mMediaButtonReceiverHolder = - MediaButtonReceiverHolder.create(mContext, mUserId, pi, mPackageName); + MediaButtonReceiverHolder.create(mContext, mUserId, pi, sessionPackageName); mService.onMediaButtonReceiverChanged(MediaSessionRecord.this); } finally { Binder.restoreCallingIdentity(token); @@ -936,7 +945,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR //mPackageName has been verified in MediaSessionService.enforcePackageName(). if (receiver != null && !TextUtils.equals( mPackageName, receiver.getPackageName())) { - EventLog.writeEvent(0x534e4554, "238177121", -1, ""); // SafetyNet Logging. + EventLog.writeEvent(0x534e4554, "238177121", -1, ""); throw new IllegalArgumentException("receiver does not belong to " + "package name provided to MediaSessionRecord. Pkg = " + mPackageName + ", Receiver Pkg = " + receiver.getPackageName()); diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java index 09035cd1d165..15c9ba923d3a 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java @@ -37,6 +37,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.util.Log; +import android.util.SparseArray; import com.android.internal.util.Preconditions; @@ -829,17 +830,41 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware @Override public void binderDied() { // This is called whenever our client process dies. + SparseArray<ModelState.Activity> cachedMap = + new SparseArray<ModelState.Activity>(); synchronized (SoundTriggerMiddlewareValidation.this) { - try { - // Gracefully stop all active recognitions and unload the models. + // Copy the relevant state under the lock, so we can call back without + // holding a lock. This exposes us to a potential race, but the client is + // dead so we don't expect one. + // TODO(240613068) A more resilient fix for this. for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) { - if (entry.getValue().activityState == ModelState.Activity.ACTIVE) { - mDelegate.stopRecognition(entry.getKey()); - } - mDelegate.unloadModel(entry.getKey()); + cachedMap.put(entry.getKey(), entry.getValue().activityState); + } + } + try { + // Gracefully stop all active recognitions and unload the models. + for (int i = 0; i < cachedMap.size(); i++) { + if (cachedMap.valueAt(i) == ModelState.Activity.ACTIVE) { + mDelegate.stopRecognition(cachedMap.keyAt(i)); } - // Detach. + mDelegate.unloadModel(cachedMap.keyAt(i)); + } + } catch (Exception e) { + throw handleException(e); + } + synchronized (SoundTriggerMiddlewareValidation.this) { + // Check if state updated unexpectedly to log race conditions. + for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) { + if (cachedMap.get(entry.getKey()) != entry.getValue().activityState) { + Log.e(TAG, "Unexpected state update in binderDied. Race occurred!"); + } + } + if (mLoadedModels.size() != cachedMap.size()) { + Log.e(TAG, "Unexpected state update in binderDied. Race occurred!"); + } + try { + // Detach detachInternal(); } catch (Exception e) { throw handleException(e); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index f8f94f655a16..58e1d053d433 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1582,13 +1582,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (newParent != null && isState(RESUMED)) { newParent.setResumedActivity(this, "onParentChanged"); - if (mStartingWindow != null && mStartingData != null - && mStartingData.mAssociatedTask == null && newParent.isEmbedded()) { - // The starting window should keep covering its task when the activity is - // reparented to a task fragment that may not fill the task bounds. - associateStartingDataWithTask(); - attachStartingSurfaceToAssociatedTask(); - } mImeInsetsFrozenUntilStartInput = false; } @@ -2679,14 +2672,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + /** Called when the starting window is added to this activity. */ void attachStartingWindow(@NonNull WindowState startingWindow) { startingWindow.mStartingData = mStartingData; mStartingWindow = startingWindow; + // The snapshot type may have called associateStartingDataWithTask(). if (mStartingData != null && mStartingData.mAssociatedTask != null) { attachStartingSurfaceToAssociatedTask(); } } + /** Makes starting window always fill the associated task. */ private void attachStartingSurfaceToAssociatedTask() { // Associate the configuration of starting window with the task. overrideConfigurationPropagation(mStartingWindow, mStartingData.mAssociatedTask); @@ -2694,6 +2690,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mStartingData.mAssociatedTask.mSurfaceControl); } + /** Called when the starting window is not added yet but its data is known to fill the task. */ private void associateStartingDataWithTask() { mStartingData.mAssociatedTask = task; task.forAllActivities(r -> { @@ -2703,6 +2700,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A }); } + /** Associates and attaches an added starting window to the current task. */ + void associateStartingWindowWithTaskIfNeeded() { + if (mStartingWindow == null || mStartingData == null + || mStartingData.mAssociatedTask != null) { + return; + } + associateStartingDataWithTask(); + attachStartingSurfaceToAssociatedTask(); + } + void removeStartingWindow() { boolean prevEligibleForLetterboxEducation = isEligibleForLetterboxEducation(); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 1c90bbae79ec..6ee018606d71 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3188,8 +3188,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this); mPointerEventDispatcher.dispose(); setRotationAnimation(null); + // Unlink death from remote to clear the reference from binder -> mRemoteInsetsDeath + // -> this DisplayContent. + setRemoteInsetsController(null); mWmService.mAnimator.removeDisplayLocked(mDisplayId); mOverlayLayer.release(); + mWindowingLayer.release(); mInputMonitor.onDisplayRemoved(); mWmService.mDisplayNotificationController.dispatchDisplayRemoved(this); mWmService.mAccessibilityController.onDisplayRemoved(mDisplayId); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index e38f5fe61888..de135a34c3df 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1436,6 +1436,13 @@ class Task extends TaskFragment { final TaskFragment childTaskFrag = child.asTaskFragment(); if (childTaskFrag != null && childTaskFrag.asTask() == null) { childTaskFrag.setMinDimensions(mMinWidth, mMinHeight); + + // The starting window should keep covering its task when a pure TaskFragment is added + // because its bounds may not fill the task. + final ActivityRecord top = getTopMostActivity(); + if (top != null) { + top.associateStartingWindowWithTaskIfNeeded(); + } } } diff --git a/services/core/xsd/display-device-config/autobrightness.xsd b/services/core/xsd/display-device-config/autobrightness.xsd new file mode 100644 index 000000000000..477625a36cbd --- /dev/null +++ b/services/core/xsd/display-device-config/autobrightness.xsd @@ -0,0 +1,33 @@ +<!-- + Copyright (C) 2022 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. +--> +<xs:schema version="2.0" + elementFormDefault="qualified" + xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:complexType name="autoBrightness"> + <xs:sequence> + <!-- Sets the debounce for autoBrightness brightening in millis--> + <xs:element name="brighteningLightDebounceMillis" type="xs:nonNegativeInteger" + minOccurs="0" maxOccurs="1"> + <xs:annotation name="final"/> + </xs:element> + <!-- Sets the debounce for autoBrightness darkening in millis--> + <xs:element name="darkeningLightDebounceMillis" type="xs:nonNegativeInteger" + minOccurs="0" maxOccurs="1"> + <xs:annotation name="final"/> + </xs:element> + </xs:sequence> + </xs:complexType> +</xs:schema>
\ No newline at end of file diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index 98f83d8c0d09..bea5e2c2de74 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -23,6 +23,7 @@ <xs:schema version="2.0" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:include schemaLocation="autobrightness.xsd" /> <xs:element name="displayConfiguration"> <xs:complexType> <xs:sequence> @@ -342,74 +343,4 @@ <xs:annotation name="final"/> </xs:element> </xs:complexType> - - <xs:complexType name="autoBrightness"> - <xs:sequence> - <!-- Sets the debounce for autoBrightness brightening in millis--> - <xs:element name="brighteningLightDebounceMillis" type="xs:nonNegativeInteger" - minOccurs="0" maxOccurs="1"> - <xs:annotation name="final"/> - </xs:element> - <!-- Sets the debounce for autoBrightness darkening in millis--> - <xs:element name="darkeningLightDebounceMillis" type="xs:nonNegativeInteger" - minOccurs="0" maxOccurs="1"> - <xs:annotation name="final"/> - </xs:element> - <!-- Sets the brightness mapping of the desired screen brightness in nits to the - corresponding lux for the current display --> - <xs:element name="displayBrightnessMapping" type="displayBrightnessMapping" - minOccurs="0" maxOccurs="1"> - <xs:annotation name="final"/> - </xs:element> - </xs:sequence> - </xs:complexType> - - <!-- Represents the brightness mapping of the desired screen brightness in nits to the - corresponding lux for the current display --> - <xs:complexType name="displayBrightnessMapping"> - <xs:sequence> - <!-- Sets the list of display brightness points, each representing the desired screen - brightness in nits to the corresponding lux for the current display - - The N entries of this array define N + 1 control points as follows: - (1-based arrays) - - Point 1: (0, nits[1]): currentLux <= 0 - Point 2: (lux[1], nits[2]): 0 < currentLux <= lux[1] - Point 3: (lux[2], nits[3]): lux[2] < currentLux <= lux[3] - ... - Point N+1: (lux[N], nits[N+1]): lux[N] < currentLux - - The control points must be strictly increasing. Each control point - corresponds to an entry in the brightness backlight values arrays. - For example, if currentLux == lux[1] (first element of the levels array) - then the brightness will be determined by nits[2] (second element - of the brightness values array). - --> - <xs:element name="displayBrightnessPoint" type="displayBrightnessPoint" - minOccurs="1" maxOccurs="unbounded"> - <xs:annotation name="final"/> - </xs:element> - </xs:sequence> - </xs:complexType> - - <!-- Represents a point in the display brightness mapping, representing the lux level from the - light sensor to the desired screen brightness in nits at this level --> - <xs:complexType name="displayBrightnessPoint"> - <xs:sequence> - <!-- The lux level from the light sensor. This must be a non-negative integer --> - <xs:element name="lux" type="xs:nonNegativeInteger" - minOccurs="1" maxOccurs="1"> - <xs:annotation name="final"/> - </xs:element> - - <!-- Desired screen brightness in nits corresponding to the suggested lux values. - The display brightness is defined as the measured brightness of an all-white image. - This must be a non-negative integer --> - <xs:element name="nits" type="xs:nonNegativeInteger" - minOccurs="1" maxOccurs="1"> - <xs:annotation name="final"/> - </xs:element> - </xs:sequence> - </xs:complexType> </xs:schema> diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt index e5d26177b725..e9a926946764 100644 --- a/services/core/xsd/display-device-config/schema/current.txt +++ b/services/core/xsd/display-device-config/schema/current.txt @@ -5,10 +5,8 @@ package com.android.server.display.config { ctor public AutoBrightness(); method public final java.math.BigInteger getBrighteningLightDebounceMillis(); method public final java.math.BigInteger getDarkeningLightDebounceMillis(); - method public final com.android.server.display.config.DisplayBrightnessMapping getDisplayBrightnessMapping(); method public final void setBrighteningLightDebounceMillis(java.math.BigInteger); method public final void setDarkeningLightDebounceMillis(java.math.BigInteger); - method public final void setDisplayBrightnessMapping(com.android.server.display.config.DisplayBrightnessMapping); } public class BrightnessThresholds { @@ -45,19 +43,6 @@ package com.android.server.display.config { method public java.util.List<com.android.server.display.config.Density> getDensity(); } - public class DisplayBrightnessMapping { - ctor public DisplayBrightnessMapping(); - method public final java.util.List<com.android.server.display.config.DisplayBrightnessPoint> getDisplayBrightnessPoint(); - } - - public class DisplayBrightnessPoint { - ctor public DisplayBrightnessPoint(); - method public final java.math.BigInteger getLux(); - method public final java.math.BigInteger getNits(); - method public final void setLux(java.math.BigInteger); - method public final void setNits(java.math.BigInteger); - } - public class DisplayConfiguration { ctor public DisplayConfiguration(); method @NonNull public final com.android.server.display.config.Thresholds getAmbientBrightnessChangeThresholds(); diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java index 03eff2a1831b..e170e98dd747 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java @@ -258,7 +258,7 @@ public final class GameServiceControllerTest { PROVIDER_A_SERVICE_A, PROVIDER_A_SERVICE_C)); FakeGameServiceProviderInstance instanceB = - seedConfigurationForUser(USER_10, configurationA); + seedConfigurationForUser(USER_10, configurationB); Intent intent = new Intent(); intent.setData(Uri.parse("package:" + PROVIDER_A_PACKAGE_NAME)); broadcastReceiverArgumentCaptor.getValue().onReceive(mMockContext, intent); diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java index e4f9eaf091e9..3f16a98c81c9 100644 --- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java @@ -28,7 +28,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -36,7 +35,6 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; -import android.Manifest; import android.annotation.Nullable; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityManagerInternal; @@ -98,7 +96,6 @@ import org.mockito.quality.Strictness; import java.util.ArrayList; import java.util.HashMap; -import java.util.Objects; import java.util.function.Consumer; @@ -361,7 +358,6 @@ public final class GameServiceProviderInstanceImplTest { throws Exception { mGameServiceProviderInstance.start(); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).isEmpty(); @@ -383,7 +379,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSessionService.CapturedCreateInvocation capturedCreateInvocation = @@ -398,7 +393,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).isEmpty(); @@ -408,7 +402,6 @@ public final class GameServiceProviderInstanceImplTest { public void gameTaskStartedAndSessionRequested_createsGameSession() throws Exception { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -426,9 +419,7 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); CreateGameSessionRequest expectedCreateGameSessionRequest = new CreateGameSessionRequest(10, @@ -442,7 +433,6 @@ public final class GameServiceProviderInstanceImplTest { public void gameSessionSuccessfullyCreated_createsTaskOverlay() throws Exception { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -462,7 +452,6 @@ public final class GameServiceProviderInstanceImplTest { startTask(10, GAME_A_MAIN_ACTIVITY); startProcessForPackage(gameProcessId, GAME_A_PACKAGE); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -488,7 +477,6 @@ public final class GameServiceProviderInstanceImplTest { startTask(11, GAME_A_MAIN_ACTIVITY); startProcessForPackage(gameProcessId, GAME_A_PACKAGE); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); mFakeGameService.requestCreateGameSession(11); @@ -522,7 +510,6 @@ public final class GameServiceProviderInstanceImplTest { startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE); startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -551,7 +538,6 @@ public final class GameServiceProviderInstanceImplTest { startTask(10, GAME_A_MAIN_ACTIVITY); startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -583,7 +569,6 @@ public final class GameServiceProviderInstanceImplTest { startTask(11, GAME_A_MAIN_ACTIVITY); startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); mFakeGameService.requestCreateGameSession(11); @@ -624,7 +609,6 @@ public final class GameServiceProviderInstanceImplTest { startTask(10, GAME_A_MAIN_ACTIVITY); startProcessForPackage(gameProcessId, GAME_A_PACKAGE); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); // No game session should be created. assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).isEmpty(); @@ -636,7 +620,6 @@ public final class GameServiceProviderInstanceImplTest { startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -677,7 +660,6 @@ public final class GameServiceProviderInstanceImplTest { public void systemBarsTransientShownDueToGesture_hasGameSession_propagatesToGameSession() { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -699,7 +681,6 @@ public final class GameServiceProviderInstanceImplTest { public void systemBarsTransientShownButNotGesture_hasGameSession_notPropagatedToGameSession() { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -721,7 +702,6 @@ public final class GameServiceProviderInstanceImplTest { public void gameTaskFocused_propagatedToGameSession() throws Exception { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -747,7 +727,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -764,7 +743,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); dispatchTaskRemoved(10); @@ -782,7 +760,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -800,7 +777,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -830,7 +806,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -851,7 +826,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -879,7 +853,6 @@ public final class GameServiceProviderInstanceImplTest { startTask(10, GAME_A_MAIN_ACTIVITY); startTask(11, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -897,7 +870,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -925,7 +897,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -955,7 +926,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -989,19 +959,10 @@ public final class GameServiceProviderInstanceImplTest { } @Test - public void createGameSession_failurePermissionDenied() throws Exception { - mGameServiceProviderInstance.start(); - startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionDenied(Manifest.permission.MANAGE_GAME_ACTIVITY); - assertThrows(SecurityException.class, () -> mFakeGameService.requestCreateGameSession(10)); - } - - @Test public void gameSessionServiceDies_severalActiveGameSessions_destroysGameSessions() { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -1030,7 +991,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -1058,7 +1018,6 @@ public final class GameServiceProviderInstanceImplTest { public void takeScreenshot_failureNoBitmapCaptured() throws Exception { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -1093,7 +1052,6 @@ public final class GameServiceProviderInstanceImplTest { any(), any(), any(), anyInt(), anyInt(), any(), anyInt(), any(), any()); mGameServiceProviderInstance.start(); startTask(taskId, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(taskId); FakeGameSession gameSession10 = new FakeGameSession(); @@ -1113,7 +1071,6 @@ public final class GameServiceProviderInstanceImplTest { @Test public void restartGame_taskIdAssociatedWithGame_restartsTargetGame() throws Exception { - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); Intent launchIntent = new Intent("com.test.ACTION_LAUNCH_GAME_PACKAGE") .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); when(mMockPackageManager.getLaunchIntentForPackage(GAME_A_PACKAGE)) @@ -1122,7 +1079,6 @@ public final class GameServiceProviderInstanceImplTest { mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -1148,11 +1104,9 @@ public final class GameServiceProviderInstanceImplTest { @Test public void restartGame_taskIdNotAssociatedWithGame_noOp() throws Exception { - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mGameServiceProviderInstance.start(); startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); mFakeGameService.requestCreateGameSession(10); FakeGameSession gameSession10 = new FakeGameSession(); @@ -1170,21 +1124,6 @@ public final class GameServiceProviderInstanceImplTest { .restartTaskActivityProcessIfVisible(anyInt(), anyString()); } - @Test - public void restartGame_failurePermissionDenied() throws Exception { - mGameServiceProviderInstance.start(); - startTask(10, GAME_A_MAIN_ACTIVITY); - mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY); - mFakeGameService.requestCreateGameSession(10); - IGameSessionController gameSessionController = Objects.requireNonNull(getOnlyElement( - mFakeGameSessionService.getCapturedCreateInvocations())).mGameSessionController; - mockPermissionDenied(Manifest.permission.MANAGE_GAME_ACTIVITY); - assertThrows(SecurityException.class, - () -> gameSessionController.restartGame(10)); - verify(mActivityTaskManagerInternal, never()) - .restartTaskActivityProcessIfVisible(anyInt(), anyString()); - } - private void startTask(int taskId, ComponentName componentName) { addRunningTaskInfo(taskId, componentName); @@ -1261,14 +1200,6 @@ public final class GameServiceProviderInstanceImplTest { } } - private void mockPermissionGranted(String permission) { - mMockContext.setPermission(permission, PackageManager.PERMISSION_GRANTED); - } - - private void mockPermissionDenied(String permission) { - mMockContext.setPermission(permission, PackageManager.PERMISSION_DENIED); - } - private void dispatchTaskSystemBarsEvent( ThrowingConsumer<TaskSystemBarsListener> taskSystemBarsListenerConsumer) { for (TaskSystemBarsListener listener : mTaskSystemBarsListeners) { @@ -1409,42 +1340,12 @@ public final class GameServiceProviderInstanceImplTest { } private final class MockContext extends ContextWrapper { - // Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant - private final HashMap<String, Integer> mMockedPermissions = new HashMap<>(); - MockContext(Context base) { super(base); } - - /** - * Mock checks for the specified permission, and have them behave as per {@code granted}. - * - * <p>Passing null reverts to default behavior, which does a real permission check on the - * test package. - * - * @param granted One of {@link PackageManager#PERMISSION_GRANTED} or - * {@link PackageManager#PERMISSION_DENIED}. - */ - public void setPermission(String permission, Integer granted) { - mMockedPermissions.put(permission, granted); - } - @Override public PackageManager getPackageManager() { return mMockPackageManager; } - - @Override - public void enforceCallingPermission(String permission, @Nullable String message) { - final Integer granted = mMockedPermissions.get(permission); - if (granted == null) { - super.enforceCallingOrSelfPermission(permission, message); - return; - } - - if (!granted.equals(PackageManager.PERMISSION_GRANTED)) { - throw new SecurityException("[Test] permission denied: " + permission); - } - } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java index 60ddeeb497a8..7755552bcad2 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -149,12 +149,6 @@ public class LocalDisplayAdapterTest { .thenReturn(mockArray); when(mMockedResources.obtainTypedArray(R.array.config_roundedCornerBottomRadiusArray)) .thenReturn(mockArray); - when(mMockedResources.obtainTypedArray( - com.android.internal.R.array.config_autoBrightnessDisplayValuesNits)) - .thenReturn(mockArray); - when(mMockedResources.obtainTypedArray( - com.android.internal.R.array.config_autoBrightnessLevels)) - .thenReturn(mockArray); } @After diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java index 45e3b4373266..eb1314194aa3 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java @@ -91,8 +91,7 @@ public class BiometricSchedulerTest { mToken = new Binder(); mScheduler = new BiometricScheduler(TAG, new Handler(TestableLooper.get(this).getLooper()), BiometricScheduler.SENSOR_TYPE_UNKNOWN, null /* gestureAvailabilityTracker */, - mBiometricService, LOG_NUM_RECENT_OPERATIONS, - CoexCoordinator.getInstance()); + mBiometricService, LOG_NUM_RECENT_OPERATIONS); } @Test diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java deleted file mode 100644 index abf992b6c637..000000000000 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java +++ /dev/null @@ -1,573 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.biometrics.sensors; - -import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FACE; -import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FP_OTHER; -import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_UDFPS; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertTrue; - -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.hardware.biometrics.BiometricConstants; -import android.platform.test.annotations.Presubmit; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; - -import com.android.server.biometrics.sensors.fingerprint.Udfps; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -import java.util.LinkedList; - -@Presubmit -@SmallTest -public class CoexCoordinatorTest { - - @Rule - public final MockitoRule mockito = MockitoJUnit.rule(); - - @Mock - private CoexCoordinator.Callback mCallback; - @Mock - private CoexCoordinator.ErrorCallback mErrorCallback; - @Mock - private AuthenticationClient mFaceClient; - @Mock - private AuthenticationClient mFingerprintClient; - @Mock(extraInterfaces = {Udfps.class}) - private AuthenticationClient mUdfpsClient; - - private CoexCoordinator mCoexCoordinator; - - @Before - public void setUp() { - mCoexCoordinator = CoexCoordinator.getInstance(); - mCoexCoordinator.setAdvancedLogicEnabled(true); - mCoexCoordinator.setFaceHapticDisabledWhenNonBypass(true); - mCoexCoordinator.reset(); - } - - @Test - public void testBiometricPrompt_authSuccess() { - when(mFaceClient.isBiometricPrompt()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - - mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, - mFaceClient, mCallback); - verify(mCallback).sendHapticFeedback(); - verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */); - verify(mCallback).handleLifecycleAfterAuth(); - } - - @Test - public void testBiometricPrompt_authReject_whenNotLockedOut() { - when(mFaceClient.isBiometricPrompt()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - - mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, - mFaceClient, LockoutTracker.LOCKOUT_NONE, mCallback); - verify(mCallback).sendHapticFeedback(); - verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */); - verify(mCallback).handleLifecycleAfterAuth(); - } - - @Test - public void testBiometricPrompt_authReject_whenLockedOut() { - when(mFaceClient.isBiometricPrompt()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - - mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, - mFaceClient, LockoutTracker.LOCKOUT_TIMED, mCallback); - verify(mCallback).sendHapticFeedback(); - verify(mCallback, never()).sendAuthenticationResult(anyBoolean()); - verify(mCallback).handleLifecycleAfterAuth(); - } - - @Test - public void testBiometricPrompt_coex_success() { - testBiometricPrompt_coex_success(false /* twice */); - } - - @Test - public void testBiometricPrompt_coex_successWithoutDouble() { - testBiometricPrompt_coex_success(true /* twice */); - } - - private void testBiometricPrompt_coex_success(boolean twice) { - initFaceAndFingerprintForBiometricPrompt(); - when(mFaceClient.wasAuthSuccessful()).thenReturn(true); - when(mUdfpsClient.wasAuthSuccessful()).thenReturn(twice, true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient); - - mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, - mFaceClient, mCallback); - mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, - mUdfpsClient, mCallback); - - if (twice) { - verify(mCallback, never()).sendHapticFeedback(); - } else { - verify(mCallback).sendHapticFeedback(); - } - } - - @Test - public void testBiometricPrompt_coex_reject() { - initFaceAndFingerprintForBiometricPrompt(); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient); - - mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, - mFaceClient, LockoutTracker.LOCKOUT_NONE, mCallback); - - verify(mCallback, never()).sendHapticFeedback(); - - mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, - mUdfpsClient, LockoutTracker.LOCKOUT_NONE, mCallback); - - verify(mCallback).sendHapticFeedback(); - } - - @Test - public void testBiometricPrompt_coex_errorNoHaptics() { - initFaceAndFingerprintForBiometricPrompt(); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient); - - mCoexCoordinator.onAuthenticationError(mFaceClient, - BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback); - mCoexCoordinator.onAuthenticationError(mUdfpsClient, - BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback); - - verify(mErrorCallback, never()).sendHapticFeedback(); - } - - private void initFaceAndFingerprintForBiometricPrompt() { - when(mFaceClient.isKeyguard()).thenReturn(false); - when(mFaceClient.isBiometricPrompt()).thenReturn(true); - when(mFaceClient.wasAuthAttempted()).thenReturn(true); - when(mUdfpsClient.isKeyguard()).thenReturn(false); - when(mUdfpsClient.isBiometricPrompt()).thenReturn(true); - when(mUdfpsClient.wasAuthAttempted()).thenReturn(true); - } - - @Test - public void testKeyguard_faceAuthOnly_success() { - when(mFaceClient.isKeyguard()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - - mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, - mFaceClient, mCallback); - verify(mCallback).sendHapticFeedback(); - verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */); - verify(mCallback).handleLifecycleAfterAuth(); - } - - @Test - public void testKeyguard_faceAuth_udfpsNotTouching_faceSuccess() { - when(mFaceClient.isKeyguard()).thenReturn(true); - - when(mUdfpsClient.isKeyguard()).thenReturn(true); - when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(false); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient); - - mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, - mFaceClient, mCallback); - // Haptics tested in #testKeyguard_bypass_haptics. Let's leave this commented out (instead - // of removed) to keep this context. - // verify(mCallback).sendHapticFeedback(); - verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */); - verify(mCallback).handleLifecycleAfterAuth(); - } - - @Test - public void testKeyguard_faceAuthSuccess_nonBypass_udfpsRunning_noHaptics() { - testKeyguard_bypass_haptics(false /* bypassEnabled */, - true /* faceAccepted */, - false /* shouldReceiveHaptics */); - } - - @Test - public void testKeyguard_faceAuthReject_nonBypass_udfpsRunning_noHaptics() { - testKeyguard_bypass_haptics(false /* bypassEnabled */, - false /* faceAccepted */, - false /* shouldReceiveHaptics */); - } - - @Test - public void testKeyguard_faceAuthSuccess_bypass_udfpsRunning_haptics() { - testKeyguard_bypass_haptics(true /* bypassEnabled */, - true /* faceAccepted */, - true /* shouldReceiveHaptics */); - } - - @Test - public void testKeyguard_faceAuthReject_bypass_udfpsRunning_haptics() { - testKeyguard_bypass_haptics(true /* bypassEnabled */, - false /* faceAccepted */, - true /* shouldReceiveHaptics */); - } - - private void testKeyguard_bypass_haptics(boolean bypassEnabled, boolean faceAccepted, - boolean shouldReceiveHaptics) { - when(mFaceClient.isKeyguard()).thenReturn(true); - when(mFaceClient.isKeyguardBypassEnabled()).thenReturn(bypassEnabled); - when(mUdfpsClient.isKeyguard()).thenReturn(true); - when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(false); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient); - - if (faceAccepted) { - mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, mFaceClient, - mCallback); - } else { - mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, mFaceClient, - LockoutTracker.LOCKOUT_NONE, mCallback); - } - - if (shouldReceiveHaptics) { - verify(mCallback).sendHapticFeedback(); - } else { - verify(mCallback, never()).sendHapticFeedback(); - } - - verify(mCallback).sendAuthenticationResult(eq(faceAccepted) /* addAuthTokenIfStrong */); - verify(mCallback).handleLifecycleAfterAuth(); - } - - @Test - public void testKeyguard_faceAuth_udfpsTouching_faceSuccess_thenUdfpsRejectedWithinBounds() { - testKeyguard_faceAuth_udfpsTouching_faceSuccess(false /* thenUdfpsAccepted */, - 0 /* udfpsRejectedAfterMs */); - } - - @Test - public void testKeyguard_faceAuth_udfpsTouching_faceSuccess_thenUdfpsRejectedAfterBounds() { - testKeyguard_faceAuth_udfpsTouching_faceSuccess(false /* thenUdfpsAccepted */, - CoexCoordinator.SUCCESSFUL_AUTH_VALID_DURATION_MS + 1 /* udfpsRejectedAfterMs */); - } - - @Test - public void testKeyguard_faceAuth_udfpsTouching_faceSuccess_thenUdfpsAccepted() { - testKeyguard_faceAuth_udfpsTouching_faceSuccess(true /* thenUdfpsAccepted */, - 0 /* udfpsRejectedAfterMs */); - } - - private void testKeyguard_faceAuth_udfpsTouching_faceSuccess(boolean thenUdfpsAccepted, - long udfpsRejectedAfterMs) { - when(mFaceClient.isKeyguard()).thenReturn(true); - when(mUdfpsClient.isKeyguard()).thenReturn(true); - when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(true); - when(mUdfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient); - - // For easier reading - final CoexCoordinator.Callback faceCallback = mCallback; - - mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, mFaceClient, - faceCallback); - verify(faceCallback, never()).sendHapticFeedback(); - verify(faceCallback, never()).sendAuthenticationResult(anyBoolean()); - // CoexCoordinator requests the system to hold onto this AuthenticationClient until - // UDFPS result is known - verify(faceCallback, never()).handleLifecycleAfterAuth(); - - // Reset the mock - CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class); - assertEquals(1, mCoexCoordinator.mSuccessfulAuths.size()); - assertEquals(mFaceClient, mCoexCoordinator.mSuccessfulAuths.get(0).mAuthenticationClient); - if (thenUdfpsAccepted) { - mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, mUdfpsClient, - udfpsCallback); - verify(udfpsCallback).sendHapticFeedback(); - verify(udfpsCallback).sendAuthenticationResult(true /* addAuthTokenIfStrong */); - verify(udfpsCallback).handleLifecycleAfterAuth(); - - verify(faceCallback).sendAuthenticationCanceled(); - - assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty()); - } else { - mCoexCoordinator.onAuthenticationRejected(udfpsRejectedAfterMs, mUdfpsClient, - LockoutTracker.LOCKOUT_NONE, udfpsCallback); - if (udfpsRejectedAfterMs <= CoexCoordinator.SUCCESSFUL_AUTH_VALID_DURATION_MS) { - verify(udfpsCallback, never()).sendHapticFeedback(); - - verify(faceCallback).sendHapticFeedback(); - verify(faceCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */); - verify(faceCallback).handleLifecycleAfterAuth(); - - assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty()); - } else { - assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty()); - - verify(faceCallback, never()).sendHapticFeedback(); - verify(faceCallback, never()).sendAuthenticationResult(anyBoolean()); - - verify(udfpsCallback).sendHapticFeedback(); - verify(udfpsCallback) - .sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */); - verify(udfpsCallback).handleLifecycleAfterAuth(); - } - } - } - - @Test - public void testKeyguard_udfpsAuthSuccess_whileFaceScanning() { - when(mFaceClient.isKeyguard()).thenReturn(true); - when(mFaceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED); - when(mUdfpsClient.isKeyguard()).thenReturn(true); - when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient); - - mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, mUdfpsClient, - mCallback); - verify(mCallback).sendHapticFeedback(); - verify(mCallback).sendAuthenticationResult(eq(true)); - verify(mFaceClient).cancel(); - verify(mCallback).handleLifecycleAfterAuth(); - } - - @Test - public void testKeyguard_faceRejectedWhenUdfpsTouching_thenUdfpsRejected() { - when(mFaceClient.isKeyguard()).thenReturn(true); - when(mFaceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED); - when(mUdfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED); - when(mUdfpsClient.isKeyguard()).thenReturn(true); - when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient); - - mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, mFaceClient, - LockoutTracker.LOCKOUT_NONE, mCallback); - verify(mCallback, never()).sendHapticFeedback(); - verify(mCallback).handleLifecycleAfterAuth(); - - // BiometricScheduler removes the face authentication client after rejection - mCoexCoordinator.removeAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - - // Then UDFPS rejected - CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class); - mCoexCoordinator.onAuthenticationRejected(1 /* currentTimeMillis */, mUdfpsClient, - LockoutTracker.LOCKOUT_NONE, udfpsCallback); - verify(udfpsCallback).sendHapticFeedback(); - verify(udfpsCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */); - verify(mCallback, never()).sendHapticFeedback(); - } - - @Test - public void testKeyguard_udfpsRejected_thenFaceRejected_noKeyguardBypass() { - when(mFaceClient.isKeyguard()).thenReturn(true); - when(mFaceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED); - when(mFaceClient.isKeyguardBypassEnabled()).thenReturn(false); // TODO: also test "true" case - when(mUdfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED); - when(mUdfpsClient.isKeyguard()).thenReturn(true); - when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient); - - mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, - mUdfpsClient, LockoutTracker.LOCKOUT_NONE, mCallback); - // Auth was attempted - when(mUdfpsClient.getState()) - .thenReturn(AuthenticationClient.STATE_STARTED_PAUSED_ATTEMPTED); - verify(mCallback).sendHapticFeedback(); - verify(mCallback).handleLifecycleAfterAuth(); - - // Then face rejected. Note that scheduler leaves UDFPS in the CoexCoordinator since - // unlike face, its lifecycle becomes "paused" instead of "finished". - CoexCoordinator.Callback faceCallback = mock(CoexCoordinator.Callback.class); - mCoexCoordinator.onAuthenticationRejected(1 /* currentTimeMillis */, mFaceClient, - LockoutTracker.LOCKOUT_NONE, faceCallback); - verify(faceCallback).sendHapticFeedback(); - verify(faceCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */); - verify(mCallback).sendHapticFeedback(); - } - - @Test - public void testKeyguard_capacitiveAccepted_whenFaceScanning() { - when(mFaceClient.isKeyguard()).thenReturn(true); - when(mFaceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED); - when(mFingerprintClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED); - when(mFingerprintClient.isKeyguard()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FP_OTHER, mFingerprintClient); - - mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, - mFingerprintClient, mCallback); - verify(mCallback).sendHapticFeedback(); - verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */); - verify(mCallback).handleLifecycleAfterAuth(); - } - - @Test - public void testKeyguard_capacitiveRejected_whenFaceScanning() { - when(mFaceClient.isKeyguard()).thenReturn(true); - when(mFaceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED); - when(mFingerprintClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED); - when(mFingerprintClient.isKeyguard()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FP_OTHER, mFingerprintClient); - - mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, - mFingerprintClient, LockoutTracker.LOCKOUT_NONE, mCallback); - verify(mCallback).sendHapticFeedback(); - verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */); - verify(mCallback).handleLifecycleAfterAuth(); - } - - @Test - public void testNonKeyguard_rejectAndNotLockedOut() { - when(mFaceClient.isKeyguard()).thenReturn(false); - when(mFaceClient.isBiometricPrompt()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, mFaceClient, - LockoutTracker.LOCKOUT_NONE, mCallback); - - verify(mCallback).sendHapticFeedback(); - verify(mCallback).sendAuthenticationResult(eq(false)); - verify(mCallback).handleLifecycleAfterAuth(); - } - - @Test - public void testNonKeyguard_rejectLockedOut() { - when(mFaceClient.isKeyguard()).thenReturn(false); - when(mFaceClient.isBiometricPrompt()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, mFaceClient, - LockoutTracker.LOCKOUT_TIMED, mCallback); - - verify(mCallback).sendHapticFeedback(); - verify(mCallback, never()).sendAuthenticationResult(anyBoolean()); - verify(mCallback).handleLifecycleAfterAuth(); - } - - @Test - public void testCleanupRunnable() { - LinkedList<CoexCoordinator.SuccessfulAuth> successfulAuths = mock(LinkedList.class); - CoexCoordinator.SuccessfulAuth auth = mock(CoexCoordinator.SuccessfulAuth.class); - CoexCoordinator.Callback callback = mock(CoexCoordinator.Callback.class); - CoexCoordinator.SuccessfulAuth.CleanupRunnable runnable = - new CoexCoordinator.SuccessfulAuth.CleanupRunnable(successfulAuths, auth, callback); - runnable.run(); - - InstrumentationRegistry.getInstrumentation().waitForIdleSync(); - - verify(callback).handleLifecycleAfterAuth(); - verify(successfulAuths).remove(eq(auth)); - } - - @Test - public void testBiometricPrompt_FaceError() { - when(mFaceClient.isBiometricPrompt()).thenReturn(true); - when(mFaceClient.wasAuthAttempted()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - - mCoexCoordinator.onAuthenticationError(mFaceClient, - BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback); - verify(mErrorCallback).sendHapticFeedback(); - } - - @Test - public void testKeyguard_faceAuthOnly_errorWhenBypassEnabled() { - testKeyguard_faceAuthOnly(true /* bypassEnabled */); - } - - @Test - public void testKeyguard_faceAuthOnly_errorWhenBypassDisabled() { - testKeyguard_faceAuthOnly(false /* bypassEnabled */); - } - - private void testKeyguard_faceAuthOnly(boolean bypassEnabled) { - when(mFaceClient.isKeyguard()).thenReturn(true); - when(mFaceClient.isKeyguardBypassEnabled()).thenReturn(bypassEnabled); - when(mFaceClient.wasAuthAttempted()).thenReturn(true); - when(mFaceClient.wasUserDetected()).thenReturn(true); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - - mCoexCoordinator.onAuthenticationError(mFaceClient, - BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback); - verify(mErrorCallback).sendHapticFeedback(); - } - - @Test - public void testKeyguard_coex_faceErrorWhenBypassEnabled() { - testKeyguard_coex_faceError(true /* bypassEnabled */); - } - - @Test - public void testKeyguard_coex_faceErrorWhenBypassDisabled() { - testKeyguard_coex_faceError(false /* bypassEnabled */); - } - - private void testKeyguard_coex_faceError(boolean bypassEnabled) { - when(mFaceClient.isKeyguard()).thenReturn(true); - when(mFaceClient.isKeyguardBypassEnabled()).thenReturn(bypassEnabled); - when(mFaceClient.wasAuthAttempted()).thenReturn(true); - when(mFaceClient.wasUserDetected()).thenReturn(true); - when(mUdfpsClient.isKeyguard()).thenReturn(true); - when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(false); - - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient); - mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient); - - mCoexCoordinator.onAuthenticationError(mFaceClient, - BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback); - - if (bypassEnabled) { - verify(mErrorCallback).sendHapticFeedback(); - } else { - verify(mErrorCallback, never()).sendHapticFeedback(); - } - } -} diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java index 0df3028805d2..0815fe52e262 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java @@ -118,8 +118,7 @@ public class UserAwareBiometricSchedulerTest { TEST_SENSOR_ID, mBiometricLogger, mBiometricContext, mUserStartedCallback, mStartOperationsFinish); } - }, - CoexCoordinator.getInstance()); + }); } @Test diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java index b60324e88f15..518946aa761a 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java @@ -35,7 +35,6 @@ import androidx.test.filters.SmallTest; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; import com.android.server.biometrics.sensors.BiometricScheduler; -import com.android.server.biometrics.sensors.CoexCoordinator; import com.android.server.biometrics.sensors.LockoutCache; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; @@ -91,8 +90,7 @@ public class SensorTest { null /* gestureAvailabilityDispatcher */, mBiometricService, () -> USER_ID, - mUserSwitchCallback, - CoexCoordinator.getInstance()); + mUserSwitchCallback); mHalCallback = new Sensor.HalSessionCallback(mContext, new Handler(mLooper.getLooper()), TAG, mScheduler, SENSOR_ID, USER_ID, mLockoutCache, mLockoutResetDispatcher, mHalSessionCallback); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java index e1a4a2d9f969..ff636c840bad 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java @@ -35,7 +35,6 @@ import androidx.test.filters.SmallTest; import com.android.server.biometrics.log.BiometricContext; import com.android.server.biometrics.log.BiometricLogger; import com.android.server.biometrics.sensors.BiometricScheduler; -import com.android.server.biometrics.sensors.CoexCoordinator; import com.android.server.biometrics.sensors.LockoutCache; import com.android.server.biometrics.sensors.LockoutResetDispatcher; import com.android.server.biometrics.sensors.LockoutTracker; @@ -91,8 +90,7 @@ public class SensorTest { null /* gestureAvailabilityDispatcher */, mBiometricService, () -> USER_ID, - mUserSwitchCallback, - CoexCoordinator.getInstance()); + mUserSwitchCallback); mHalCallback = new Sensor.HalSessionCallback(mContext, new Handler(mLooper.getLooper()), TAG, mScheduler, SENSOR_ID, USER_ID, mLockoutCache, mLockoutResetDispatcher, mHalSessionCallback); diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java index 261b882319d8..03ea6137074d 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java @@ -19,19 +19,16 @@ package com.android.server.display; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.anyFloat; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; -import android.content.res.TypedArray; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -55,16 +52,22 @@ public final class DisplayDeviceConfigTest { private Resources mResources; @Before - public void setUp() { + public void setUp() throws IOException { MockitoAnnotations.initMocks(this); when(mContext.getResources()).thenReturn(mResources); mockDeviceConfigs(); + try { + Path tempFile = Files.createTempFile("display_config", ".tmp"); + Files.write(tempFile, getContent().getBytes(StandardCharsets.UTF_8)); + mDisplayDeviceConfig = new DisplayDeviceConfig(mContext); + mDisplayDeviceConfig.initFromFile(tempFile.toFile()); + } catch (IOException e) { + throw new IOException("Failed to setup the display device config.", e); + } } @Test - public void testConfigValuesFromDisplayConfig() throws IOException { - setupDisplayDeviceConfigFromDisplayConfigFile(); - + public void testConfigValues() { assertEquals(mDisplayDeviceConfig.getAmbientHorizonLong(), 5000); assertEquals(mDisplayDeviceConfig.getAmbientHorizonShort(), 50); assertEquals(mDisplayDeviceConfig.getBrightnessRampDecreaseMaxMillis(), 3000); @@ -85,24 +88,10 @@ public final class DisplayDeviceConfigTest { assertEquals(mDisplayDeviceConfig.getScreenDarkeningMinThreshold(), 0.002, 0.000001f); assertEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLightDebounce(), 2000); assertEquals(mDisplayDeviceConfig.getAutoBrightnessDarkeningLightDebounce(), 1000); - assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new - float[]{50.0f, 80.0f}, 0.0f); - assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new - float[]{45.0f, 75.0f}, 0.0f); - // Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping, - // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor. - } - @Test - public void testConfigValuesFromDeviceConfig() { - setupDisplayDeviceConfigFromDeviceConfigFile(); - assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new - float[]{0.0f, 110.0f, 500.0f}, 0.0f); - assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new - float[]{2.0f, 200.0f, 600.0f}, 0.0f); // Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping, // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor. - + // Also add test for the case where optional display configs are null } private String getContent() { @@ -125,16 +114,6 @@ public final class DisplayDeviceConfigTest { + "<autoBrightness>\n" + "<brighteningLightDebounceMillis>2000</brighteningLightDebounceMillis>\n" + "<darkeningLightDebounceMillis>1000</darkeningLightDebounceMillis>\n" - + "<displayBrightnessMapping>\n" - + "<displayBrightnessPoint>\n" - + "<lux>50</lux>\n" - + "<nits>45</nits>\n" - + "</displayBrightnessPoint>\n" - + "<displayBrightnessPoint>\n" - + "<lux>80</lux>\n" - + "<nits>75</nits>\n" - + "</displayBrightnessPoint>\n" - + "</displayBrightnessMapping>\n" + "</autoBrightness>\n" + "<highBrightnessMode enabled=\"true\">\n" + "<transitionPoint>0.62</transitionPoint>\n" @@ -206,64 +185,4 @@ public final class DisplayDeviceConfigTest { when(mResources.getFloat(com.android.internal.R.dimen .config_screenBrightnessSettingMaximumFloat)).thenReturn(1.0f); } - - private void setupDisplayDeviceConfigFromDisplayConfigFile() throws IOException { - Path tempFile = Files.createTempFile("display_config", ".tmp"); - Files.write(tempFile, getContent().getBytes(StandardCharsets.UTF_8)); - mDisplayDeviceConfig = new DisplayDeviceConfig(mContext); - mDisplayDeviceConfig.initFromFile(tempFile.toFile()); - } - - private void setupDisplayDeviceConfigFromDeviceConfigFile() { - TypedArray screenBrightnessNits = createFloatTypedArray(new float[]{2.0f, 250.0f, 650.0f}); - when(mResources.obtainTypedArray( - com.android.internal.R.array.config_screenBrightnessNits)) - .thenReturn(screenBrightnessNits); - TypedArray screenBrightnessBacklight = createFloatTypedArray(new - float[]{0.0f, 120.0f, 255.0f}); - when(mResources.obtainTypedArray( - com.android.internal.R.array.config_screenBrightnessBacklight)) - .thenReturn(screenBrightnessBacklight); - when(mResources.getIntArray(com.android.internal.R.array - .config_screenBrightnessBacklight)).thenReturn(new int[]{0, 120, 255}); - - when(mResources.getIntArray(com.android.internal.R.array - .config_autoBrightnessLevels)).thenReturn(new int[]{30, 80}); - when(mResources.getIntArray(com.android.internal.R.array - .config_autoBrightnessDisplayValuesNits)).thenReturn(new int[]{25, 55}); - - TypedArray screenBrightnessLevelNits = createFloatTypedArray(new - float[]{2.0f, 200.0f, 600.0f}); - when(mResources.obtainTypedArray( - com.android.internal.R.array.config_autoBrightnessDisplayValuesNits)) - .thenReturn(screenBrightnessLevelNits); - TypedArray screenBrightnessLevelLux = createFloatTypedArray(new - float[]{0.0f, 110.0f, 500.0f}); - when(mResources.obtainTypedArray( - com.android.internal.R.array.config_autoBrightnessLevels)) - .thenReturn(screenBrightnessLevelLux); - - mDisplayDeviceConfig = DisplayDeviceConfig.create(mContext, true); - - } - - private TypedArray createFloatTypedArray(float[] vals) { - TypedArray mockArray = mock(TypedArray.class); - when(mockArray.length()).thenAnswer(invocation -> { - return vals.length; - }); - when(mockArray.getFloat(anyInt(), anyFloat())).thenAnswer(invocation -> { - final float def = (float) invocation.getArguments()[1]; - if (vals == null) { - return def; - } - int idx = (int) invocation.getArguments()[0]; - if (idx >= 0 && idx < vals.length) { - return vals[idx]; - } else { - return def; - } - }); - return mockArray; - } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 44494831eb68..25c8f145bd62 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2869,6 +2869,7 @@ public class ActivityRecordTests extends WindowTestsBase { mAtm, null /* fragmentToken */, false /* createdByOrganizer */); fragmentSetup.accept(taskFragment1, new Rect(0, 0, width / 2, height)); task.addChild(taskFragment1, POSITION_TOP); + assertEquals(task, activity1.mStartingData.mAssociatedTask); final TaskFragment taskFragment2 = new TaskFragment( mAtm, null /* fragmentToken */, false /* createdByOrganizer */); @@ -2890,7 +2891,6 @@ public class ActivityRecordTests extends WindowTestsBase { eq(task.mSurfaceControl)); assertEquals(activity1.mStartingData, startingWindow.mStartingData); assertEquals(task.mSurfaceControl, startingWindow.getAnimationLeashParent()); - assertEquals(task, activity1.mStartingData.mAssociatedTask); assertEquals(taskFragment1.getBounds(), activity1.getBounds()); // The activity was resized by task fragment, but starting window must still cover the task. assertEquals(taskBounds, activity1.mStartingWindow.getBounds()); @@ -2898,7 +2898,6 @@ public class ActivityRecordTests extends WindowTestsBase { // The starting window is only removed when all embedded activities are drawn. final WindowState activityWindow = mock(WindowState.class); activity1.onFirstWindowDrawn(activityWindow); - assertNotNull(activity1.mStartingWindow); activity2.onFirstWindowDrawn(activityWindow); assertNull(activity1.mStartingWindow); } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt index 3853af2f609e..1a40f82654ff 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt @@ -164,7 +164,6 @@ class OpenActivityEmbeddingPlaceholderSplit( fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 1, supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90), supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY, diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt index 9cc1bfe81c8c..ec2b4fa35c41 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt @@ -95,7 +95,7 @@ class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio @JvmStatic fun getParams(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = 3) + .getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt index 58a80112c85e..55d412927ba6 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt @@ -103,7 +103,7 @@ class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransitio @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = 3) + .getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt index f6f3f58f29cb..725c10a8ada0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt @@ -113,8 +113,7 @@ class CloseImeAutoOpenWindowToAppTest(testSpec: FlickerTestParameter) : BaseTest fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 3, - // b/190352379 (IME doesn't show on app launch in 90 degrees) + // b/190352379 (IME doesn't show on app launch in 90 degrees) supportedRotations = listOf(Surface.ROTATION_0), supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY, diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt index 52f561ec4497..8832686b43aa 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt @@ -123,7 +123,7 @@ class CloseImeAutoOpenWindowToHomeTest(testSpec: FlickerTestParameter) : BaseTes @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = 3, + .getConfigNonRotationTests( // b/190352379 (IME doesn't show on app launch in 90 degrees) supportedRotations = listOf(Surface.ROTATION_0), supportedNavigationModes = listOf( diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt index c6e25d3de4cd..71e0aa1f9628 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt @@ -141,7 +141,6 @@ class CloseImeEditorPopupDialogTest(testSpec: FlickerTestParameter) : BaseTest(t fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 2, supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY, WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt index 23bd2200397a..0f91fd58abb7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt @@ -121,7 +121,7 @@ class CloseImeWindowToAppTest(testSpec: FlickerTestParameter) : BaseTest(testSpe @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = 3) + .getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt index 8ce184072d32..007a4f1835d7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt @@ -134,8 +134,7 @@ class CloseImeWindowToHomeTest(testSpec: FlickerTestParameter) : BaseTest(testSp fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 3, - supportedRotations = listOf(Surface.ROTATION_0), + supportedRotations = listOf(Surface.ROTATION_0), supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY, WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt index a04a50f02c26..216e0edaf451 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt @@ -127,14 +127,13 @@ class LaunchAppShowImeAndDialogThemeAppTest( @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests( - repetitions = 3, - supportedRotations = listOf(Surface.ROTATION_0), - supportedNavigationModes = listOf( - WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY, - WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY - ) + .getConfigNonRotationTests( + supportedRotations = listOf(Surface.ROTATION_0), + supportedNavigationModes = listOf( + WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY, + WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY ) + ) } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt index 04e4bc94de9c..868290ec7585 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt @@ -141,8 +141,7 @@ class LaunchAppShowImeOnStartTest(testSpec: FlickerTestParameter) : BaseTest(tes fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 3, - supportedRotations = listOf(Surface.ROTATION_0), + supportedRotations = listOf(Surface.ROTATION_0), supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY, WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt index b10aed30e39e..16c23b93a5de 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt @@ -82,8 +82,7 @@ class OpenImeWindowAndCloseTest(testSpec: FlickerTestParameter) : BaseTest(testS fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 3, - supportedRotations = listOf(Surface.ROTATION_0), + supportedRotations = listOf(Surface.ROTATION_0), supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY, WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt index d9008158ffaf..e5874921ddfa 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt @@ -117,8 +117,7 @@ class OpenImeWindowFromFixedOrientationAppTest( fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 3, - supportedRotations = listOf(Surface.ROTATION_90), + supportedRotations = listOf(Surface.ROTATION_90), supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY ) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt index fdc2193b7eb8..c1f17f3deb2e 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt @@ -95,8 +95,7 @@ class OpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) { fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 3, - supportedRotations = listOf(Surface.ROTATION_0), + supportedRotations = listOf(Surface.ROTATION_0), supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY, WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt index 9475734ef3f5..5fd94427dc82 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt @@ -265,7 +265,6 @@ class OpenImeWindowToOverViewTest(testSpec: FlickerTestParameter) : BaseTest(tes fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 1, supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90), supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY, diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt index 2e22e6224813..0281a60bbc3b 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt @@ -192,8 +192,7 @@ open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSp fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 3, - supportedRotations = listOf(Surface.ROTATION_0) + supportedRotations = listOf(Surface.ROTATION_0) ) } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt index 4f47ec439da8..85bf6d752bf5 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt @@ -200,8 +200,7 @@ open class SwitchImeWindowsFromGestureNavTest( fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 3, - supportedNavigationModes = listOf( + supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY ), supportedRotations = listOf(Surface.ROTATION_0) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt index 33c280ea78bb..eb9acc4b8e4e 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt @@ -142,7 +142,7 @@ class ActivitiesTransitionTest(testSpec: FlickerTestParameter) : BaseTest(testSp @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = 3) + .getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt index bfc7b39f9d9f..b3db5b70fafa 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt @@ -171,7 +171,7 @@ open class OpenAppFromLockNotificationCold(testSpec: FlickerTestParameter) : @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = 3) + .getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt index f93d7a0b09e3..8c1d244b69e0 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt @@ -221,7 +221,7 @@ open class OpenAppFromLockNotificationWarm(testSpec: FlickerTestParameter) : @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = 3) + .getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt index 75311eaf5c66..caf2e2dbadc6 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt @@ -127,7 +127,7 @@ class OpenAppFromLockNotificationWithLockOverlayApp(testSpec: FlickerTestParamet @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = 3) + .getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt index dbe541882fa8..e744d44bc542 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt @@ -157,7 +157,7 @@ open class OpenAppFromNotificationCold( @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = 3) + .getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt index 915b70289055..4ea42433e054 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt @@ -284,7 +284,7 @@ open class OpenAppFromNotificationWarm( @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = 3) + .getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt index 7c07ace06b82..a3dd0cbcf64f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt @@ -130,7 +130,7 @@ open class OpenAppFromOverviewTest( @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = 3) + .getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt index 53be7d43cce8..82e30accb341 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt @@ -233,8 +233,7 @@ open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 3, - supportedNavigationModes = + supportedNavigationModes = listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY), supportedRotations = listOf(Surface.ROTATION_0) ) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt index fe5e74b87f93..5f342a00bf8c 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt @@ -263,7 +263,7 @@ class TaskTransitionTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) { @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigNonRotationTests(repetitions = 3) + .getConfigNonRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt index 181767b3448d..f85bad33c4fd 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt @@ -278,8 +278,7 @@ open class QuickSwitchBetweenTwoAppsBackTest( fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 3, - supportedNavigationModes = listOf( + supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY ), supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt index 0f05622c81bc..f6392cab4a35 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt @@ -298,8 +298,7 @@ open class QuickSwitchBetweenTwoAppsForwardTest( fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 3, - supportedNavigationModes = listOf( + supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY ), supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt index d1f356c830eb..a714111fae21 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt @@ -324,8 +324,7 @@ class QuickSwitchFromLauncherTest(testSpec: FlickerTestParameter) : BaseTest(tes fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() .getConfigNonRotationTests( - repetitions = 3, - supportedNavigationModes = listOf( + supportedNavigationModes = listOf( WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY ), // TODO: Test with 90 rotation diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt index 4be8963bf7b7..e6c1eaca9380 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt @@ -146,7 +146,7 @@ class ChangeAppRotationTest( @JvmStatic fun getParams(): Collection<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigRotationTests(repetitions = 3) + .getConfigRotationTests() } } } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt index 0912812afef9..07c213034642 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt @@ -241,7 +241,7 @@ open class SeamlessAppRotationTest( @JvmStatic private fun getConfigurations(): List<FlickerTestParameter> { return FlickerTestParameterFactory.getInstance() - .getConfigRotationTests(repetitions = 2) + .getConfigRotationTests() .flatMap { sourceConfig -> val defaultRun = createConfig(sourceConfig, starveUiThread = false) val busyUiRun = createConfig(sourceConfig, starveUiThread = true) diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java index 8b69db707d41..dc34cb6d6a53 100644 --- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java +++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java @@ -15,21 +15,25 @@ */ package com.google.android.test.handwritingime; +import android.R; import android.annotation.Nullable; import android.graphics.PointF; import android.graphics.RectF; import android.inputmethodservice.InputMethodService; -import android.os.Bundle; import android.util.Log; -import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.Window; -import android.view.inputmethod.CursorAnchorInfo; +import android.view.inputmethod.DeleteGesture; +import android.view.inputmethod.HandwritingGesture; +import android.view.inputmethod.InputConnection; +import android.view.inputmethod.InsertGesture; +import android.view.inputmethod.SelectGesture; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.FrameLayout; +import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.Toast; @@ -39,19 +43,19 @@ public class HandwritingIme extends InputMethodService { public static final int HEIGHT_DP = 100; - private static final int OP_NONE = 0; private static final int OP_SELECT = 1; private static final int OP_DELETE = 2; - private static final int OP_DELETE_SPACE = 3; - private static final int OP_INSERT = 4; + private static final int OP_INSERT = 3; private Window mInkWindow; private InkView mInk; static final String TAG = "HandwritingIme"; private int mRichGestureMode = OP_NONE; + private int mRichGestureGranularity = -1; private Spinner mRichGestureModeSpinner; + private Spinner mRichGestureGranularitySpinner; private PointF mRichGestureStartPoint; @@ -86,13 +90,45 @@ public class HandwritingIme extends InputMethodService { switch (event.getAction()) { case MotionEvent.ACTION_UP: { if (areRichGesturesEnabled()) { - Bundle bundle = new Bundle(); - bundle.putInt("operation", mRichGestureMode); - bundle.putFloat("left", mRichGestureStartPoint.x); - bundle.putFloat("top", mRichGestureStartPoint.y); - bundle.putFloat("right", event.getX()); - bundle.putFloat("bottom", event.getY()); - performPrivateCommand("android.widget.RichGesture", bundle); + HandwritingGesture gesture = null; + switch(mRichGestureMode) { + case OP_SELECT: + SelectGesture.Builder builder = new SelectGesture.Builder(); + builder.setGranularity(mRichGestureGranularity) + .setSelectionArea(new RectF(mRichGestureStartPoint.x, + mRichGestureStartPoint.y, event.getX(), event.getY())) + .setFallbackText("fallback text"); + gesture = builder.build(); + break; + case OP_DELETE: + DeleteGesture.Builder builder1 = new DeleteGesture.Builder(); + builder1.setGranularity(mRichGestureGranularity) + .setDeletionArea(new RectF(mRichGestureStartPoint.x, + mRichGestureStartPoint.y, event.getX(), event.getY())) + .setFallbackText("fallback text"); + gesture = builder1.build(); + break; + case OP_INSERT: + InsertGesture.Builder builder2 = new InsertGesture.Builder(); + builder2.setInsertionPoint( + new PointF(mRichGestureStartPoint.x, mRichGestureStartPoint.y)) + .setTextToInsert(" ") + .setFallbackText("fallback text"); + gesture = builder2.build(); + + } + if (gesture == null) { + // This shouldn't happen + Log.e(TAG, "Unrecognized gesture mode: " + mRichGestureMode); + return; + } + InputConnection ic = getCurrentInputConnection(); + if (getCurrentInputStarted() && ic != null) { + ic.performHandwritingGesture(gesture, null, null); + } else { + // This shouldn't happen + Log.e(TAG, "No active InputConnection"); + } Log.d(TAG, "Sending RichGesture " + mRichGestureMode + " (Screen) Left: " + mRichGestureStartPoint.x + ", Top: " + mRichGestureStartPoint.y @@ -123,8 +159,15 @@ public class HandwritingIme extends InputMethodService { view.addView(inner, new FrameLayout.LayoutParams( FrameLayout.LayoutParams.MATCH_PARENT, height)); - view.addView(getRichGestureActionsSpinner()); - inner.setBackgroundColor(getColor(R.color.abc_tint_spinner)); + LinearLayout layout = new LinearLayout(this); + layout.setLayoutParams(new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + layout.setOrientation(LinearLayout.VERTICAL); + layout.addView(getRichGestureActionsSpinner()); + layout.addView(getRichGestureGranularitySpinner()); + + view.addView(layout); + inner.setBackgroundColor(getColor(R.color.holo_green_light)); return view; } @@ -133,14 +176,12 @@ public class HandwritingIme extends InputMethodService { if (mRichGestureModeSpinner != null) { return mRichGestureModeSpinner; } - //get the spinner from the xml. mRichGestureModeSpinner = new Spinner(this); mRichGestureModeSpinner.setPadding(100, 0, 100, 0); mRichGestureModeSpinner.setTooltipText("Handwriting IME mode"); String[] items = new String[] { "Handwriting IME - Rich gesture disabled", "Rich gesture SELECT", - "Rich gesture DELETE", "Rich gesture DELETE SPACE", - "Rich gesture INSERT" }; + "Rich gesture DELETE", "Rich gesture INSERT" }; ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_dropdown_item, items); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); @@ -149,17 +190,52 @@ public class HandwritingIme extends InputMethodService { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { mRichGestureMode = position; + mRichGestureGranularitySpinner.setEnabled( + mRichGestureMode != OP_INSERT && mRichGestureMode != OP_NONE); Log.d(TAG, "Setting RichGesture Mode " + mRichGestureMode); } @Override public void onNothingSelected(AdapterView<?> parent) { mRichGestureMode = OP_NONE; + mRichGestureGranularitySpinner.setEnabled(false); } }); + mRichGestureModeSpinner.setSelection(0); // default disabled return mRichGestureModeSpinner; } + private View getRichGestureGranularitySpinner() { + if (mRichGestureGranularitySpinner != null) { + return mRichGestureGranularitySpinner; + } + mRichGestureGranularitySpinner = new Spinner(this); + mRichGestureGranularitySpinner.setPadding(100, 0, 100, 0); + mRichGestureGranularitySpinner.setTooltipText(" Granularity"); + String[] items = + new String[] { "Granularity - UNDEFINED", + "Granularity - WORD", "Granularity - CHARACTER"}; + ArrayAdapter<String> adapter = new ArrayAdapter<>(this, + android.R.layout.simple_spinner_dropdown_item, items); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + mRichGestureGranularitySpinner.setAdapter(adapter); + mRichGestureGranularitySpinner.setOnItemSelectedListener( + new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + mRichGestureGranularity = position; + Log.d(TAG, "Setting RichGesture Granularity " + mRichGestureGranularity); + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + mRichGestureGranularity = 0; + } + }); + mRichGestureGranularitySpinner.setSelection(1); + return mRichGestureGranularitySpinner; + } + public void onPrepareStylusHandwriting() { Log.d(TAG, "onPrepareStylusHandwriting "); if (mInk == null) { @@ -190,15 +266,6 @@ public class HandwritingIme extends InputMethodService { return false; } - boolean performPrivateCommand(String action, Bundle bundle) { - if (!getCurrentInputStarted()) { - Log.e(TAG, "Input hasnt started, can't performPrivateCommand"); - return false; - } - - return getCurrentInputConnection().performPrivateCommand(action, bundle); - } - private boolean areRichGesturesEnabled() { return mRichGestureMode != OP_NONE; } diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java index c9e429b6f4c8..94b1f863f197 100644 --- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java +++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java @@ -30,7 +30,7 @@ import android.view.WindowManager; import android.view.WindowMetrics; class InkView extends View { - private static final long FINISH_TIMEOUT = 600; + private static final long FINISH_TIMEOUT = 1500; private final HandwritingIme.HandwritingFinisher mHwCanceller; private final HandwritingIme.StylusConsumer mConsumer; private final int mTopInset; diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp index 9f6ce4e8425b..b7c4c5b28168 100644 --- a/tests/RollbackTest/Android.bp +++ b/tests/RollbackTest/Android.bp @@ -61,6 +61,7 @@ java_test_host { static_libs: ["RollbackTestLib", "frameworks-base-hostutils"], test_suites: ["general-tests"], test_config: "NetworkStagedRollbackTest.xml", + data: [":RollbackTest"], } java_test_host { diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp index 1709e1501537..ffde8c7d342c 100644 --- a/tests/StagedInstallTest/Android.bp +++ b/tests/StagedInstallTest/Android.bp @@ -58,6 +58,7 @@ java_test_host { ":apex.apexd_test", ":com.android.apex.apkrollback.test_v1", ":com.android.apex.apkrollback.test_v2", + ":StagedInstallInternalTestApp", ":StagedInstallTestApexV2", ":StagedInstallTestApexV2_WrongSha", ":TestAppAv1", diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index 46a846bce35f..4fb7ed19ed20 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -369,9 +369,13 @@ class PackageFlattener { bool sparse_encode = use_sparse_entries_; - // Only sparse encode if the entries will be read on platforms O+. - sparse_encode = - sparse_encode && (context_->GetMinSdkVersion() >= SDK_O || config.sdkVersion >= SDK_O); + if (context_->GetMinSdkVersion() == 0 && config.sdkVersion == 0) { + // Sparse encode if sdk version is not set in context and config. + } else { + // Otherwise, only sparse encode if the entries will be read on platforms S_V2+. + sparse_encode = sparse_encode && + (context_->GetMinSdkVersion() >= SDK_S_V2 || config.sdkVersion >= SDK_S_V2); + } // Only sparse encode if the offsets are representable in 2 bytes. sparse_encode = diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index e48fca61fef8..f551bf61dc06 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -330,7 +330,7 @@ TEST_F(TableFlattenerTest, FlattenSparseEntryWithMinSdkO) { std::unique_ptr<IAaptContext> context = test::ContextBuilder() .SetCompilationPackage("android") .SetPackageId(0x01) - .SetMinSdkVersion(SDK_O) + .SetMinSdkVersion(SDK_S_V2) .Build(); const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB"); @@ -376,7 +376,26 @@ TEST_F(TableFlattenerTest, FlattenSparseEntryWithConfigSdkVersionO) { .SetMinSdkVersion(SDK_LOLLIPOP) .Build(); - const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB-v26"); + const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB-v32"); + auto table_in = BuildTableWithSparseEntries(context.get(), sparse_config, 0.25f); + + TableFlattenerOptions options; + options.use_sparse_entries = true; + + std::string no_sparse_contents; + ASSERT_TRUE(Flatten(context.get(), {}, table_in.get(), &no_sparse_contents)); + + std::string sparse_contents; + ASSERT_TRUE(Flatten(context.get(), options, table_in.get(), &sparse_contents)); + + EXPECT_GT(no_sparse_contents.size(), sparse_contents.size()); +} + +TEST_F(TableFlattenerTest, FlattenSparseEntryWithSdkVersionNotSet) { + std::unique_ptr<IAaptContext> context = + test::ContextBuilder().SetCompilationPackage("android").SetPackageId(0x01).Build(); + + const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB"); auto table_in = BuildTableWithSparseEntries(context.get(), sparse_config, 0.25f); TableFlattenerOptions options; @@ -389,6 +408,27 @@ TEST_F(TableFlattenerTest, FlattenSparseEntryWithConfigSdkVersionO) { ASSERT_TRUE(Flatten(context.get(), options, table_in.get(), &sparse_contents)); EXPECT_GT(no_sparse_contents.size(), sparse_contents.size()); + + // Attempt to parse the sparse contents. + + ResourceTable sparse_table; + BinaryResourceParser parser(context->GetDiagnostics(), &sparse_table, Source("test.arsc"), + sparse_contents.data(), sparse_contents.size()); + ASSERT_TRUE(parser.Parse()); + + auto value = test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_0", + sparse_config); + ASSERT_THAT(value, NotNull()); + EXPECT_EQ(0u, value->value.data); + + ASSERT_THAT(test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_1", + sparse_config), + IsNull()); + + value = test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_4", + sparse_config); + ASSERT_THAT(value, NotNull()); + EXPECT_EQ(4u, value->value.data); } TEST_F(TableFlattenerTest, DoNotUseSparseEntryForDenseConfig) { |