diff options
1158 files changed, 31446 insertions, 11949 deletions
diff --git a/Android.bp b/Android.bp index 019bf6508774..5ada10d19f5d 100644 --- a/Android.bp +++ b/Android.bp @@ -386,7 +386,7 @@ java_defaults { // TODO(b/120066492): remove gps_debug and protolog.conf.json when the build // system propagates "required" properly. "gps_debug.conf", - "protolog.conf.json.gz", + "core.protolog.pb", "framework-res", // any install dependencies should go into framework-minus-apex-install-dependencies // rather than here to avoid bloating incremental build time diff --git a/INPUT_OWNERS b/INPUT_OWNERS index 44b2f3805495..06ead06fc13a 100644 --- a/INPUT_OWNERS +++ b/INPUT_OWNERS @@ -1,4 +1,6 @@ # Bug component: 136048 +arpitks@google.com +asmitapoddar@google.com hcutts@google.com joseprio@google.com michaelwr@google.com @@ -32,6 +32,7 @@ per-file **.bp,**.mk = hansson@google.com, joeo@google.com, lamontjones@google.c per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS +per-file INPUT_OWNERS = file:/INPUT_OWNERS per-file ZYGOTE_OWNERS = file:/ZYGOTE_OWNERS per-file SQLITE_OWNERS = file:/SQLITE_OWNERS diff --git a/Ravenwood.bp b/Ravenwood.bp index 2df6d5811d44..c73e04896173 100644 --- a/Ravenwood.bp +++ b/Ravenwood.bp @@ -145,6 +145,16 @@ java_library { } java_library { + name: "services.fakes.ravenwood-jarjar", + installable: false, + srcs: [":services.fakes-sources"], + libs: [ + "services.core.ravenwood", + ], + jarjar_rules: ":ravenwood-services-jarjar-rules", +} + +java_library { name: "mockito-ravenwood-prebuilt", installable: false, static_libs: [ @@ -189,6 +199,7 @@ android_ravenwood_libgroup { "ravenwood-helper-runtime", "hoststubgen-helper-runtime.ravenwood", "services.core.ravenwood-jarjar", + "services.fakes.ravenwood-jarjar", // Provide runtime versions of utils linked in below "junit", @@ -197,6 +208,9 @@ android_ravenwood_libgroup { "mockito-ravenwood-prebuilt", "inline-mockito-ravenwood-prebuilt", ], + jni_libs: [ + "libandroid_runtime", + ], } android_ravenwood_libgroup { diff --git a/apex/jobscheduler/service/aconfig/device_idle.aconfig b/apex/jobscheduler/service/aconfig/device_idle.aconfig index fc24b3075f14..e4cb5ad81ba0 100644 --- a/apex/jobscheduler/service/aconfig/device_idle.aconfig +++ b/apex/jobscheduler/service/aconfig/device_idle.aconfig @@ -4,5 +4,5 @@ flag { name: "disable_wakelocks_in_light_idle" namespace: "backstage_power" description: "Disable wakelocks for background apps while Light Device Idle is active" - bug: "299329948" + bug: "326607666" } diff --git a/apex/jobscheduler/service/aconfig/job.aconfig b/apex/jobscheduler/service/aconfig/job.aconfig index ef9ac73d6f8e..5e6d3775f6a2 100644 --- a/apex/jobscheduler/service/aconfig/job.aconfig +++ b/apex/jobscheduler/service/aconfig/job.aconfig @@ -4,7 +4,7 @@ flag { name: "batch_active_bucket_jobs" namespace: "backstage_power" description: "Include jobs in the ACTIVE bucket in the job batching effort. Don't let them run as freely as they're ready." - bug: "299329948" + bug: "326607666" } flag { diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java index aec464d0e820..e96d07f44b34 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java @@ -55,6 +55,7 @@ import android.util.SparseArray; import android.util.SparseArrayMap; import android.util.SparseIntArray; import android.util.SparseLongArray; +import android.util.SparseSetArray; import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; @@ -158,19 +159,6 @@ public final class FlexibilityController extends StateController { @GuardedBy("mLock") private final SparseLongArray mLastSeenConstraintTimesElapsed = new SparseLongArray(); - private DeviceIdleInternal mDeviceIdleInternal; - private final ArraySet<String> mPowerAllowlistedApps = new ArraySet<>(); - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - switch (intent.getAction()) { - case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED: - mHandler.post(FlexibilityController.this::updatePowerAllowlistCache); - break; - } - } - }; @VisibleForTesting @GuardedBy("mLock") final FlexibilityTracker mFlexibilityTracker; @@ -182,6 +170,7 @@ public final class FlexibilityController extends StateController { private final FcHandler mHandler; @VisibleForTesting final PrefetchController mPrefetchController; + private final SpecialAppTracker mSpecialAppTracker; /** * Stores the beginning of prefetch jobs lifecycle per app as a maximum of @@ -355,16 +344,16 @@ public final class FlexibilityController extends StateController { mPercentsToDropConstraints = FcConfig.DEFAULT_PERCENTS_TO_DROP_FLEXIBLE_CONSTRAINTS; mPrefetchController = prefetchController; + mSpecialAppTracker = new SpecialAppTracker(); if (mFlexibilityEnabled) { - registerBroadcastReceiver(); + mSpecialAppTracker.startTracking(); } } @Override public void onSystemServicesReady() { - mDeviceIdleInternal = LocalServices.getService(DeviceIdleInternal.class); - mHandler.post(FlexibilityController.this::updatePowerAllowlistCache); + mSpecialAppTracker.onSystemServicesReady(); } @Override @@ -453,6 +442,7 @@ public final class FlexibilityController extends StateController { final int userId = UserHandle.getUserId(uid); mPrefetchLifeCycleStart.delete(userId, packageName); mJobScoreTrackers.delete(uid, packageName); + mSpecialAppTracker.onAppRemoved(userId, packageName); for (int i = mJobsToCheck.size() - 1; i >= 0; --i) { final JobStatus js = mJobsToCheck.valueAt(i); if ((js.getSourceUid() == uid && js.getSourcePackageName().equals(packageName)) @@ -466,6 +456,7 @@ public final class FlexibilityController extends StateController { @GuardedBy("mLock") public void onUserRemovedLocked(int userId) { mPrefetchLifeCycleStart.delete(userId); + mSpecialAppTracker.onUserRemoved(userId); for (int u = mJobScoreTrackers.numMaps() - 1; u >= 0; --u) { final int uid = mJobScoreTrackers.keyAt(u); if (UserHandle.getUserId(uid) == userId) { @@ -496,9 +487,10 @@ public final class FlexibilityController extends StateController { // Only exclude DEFAULT+ priority jobs for BFGS+ apps || (mService.getUidBias(js.getSourceUid()) >= JobInfo.BIAS_BOUND_FOREGROUND_SERVICE && js.getEffectivePriority() >= PRIORITY_DEFAULT) - // For apps in the power allowlist, automatically exclude DEFAULT+ priority jobs. + // For special/privileged apps, automatically exclude DEFAULT+ priority jobs. || (js.getEffectivePriority() >= PRIORITY_DEFAULT - && mPowerAllowlistedApps.contains(js.getSourcePackageName())) + && mSpecialAppTracker.isSpecialApp( + js.getSourceUserId(), js.getSourcePackageName())) || hasEnoughSatisfiedConstraintsLocked(js) || mService.isCurrentlyRunningLocked(js); } @@ -827,39 +819,6 @@ public final class FlexibilityController extends StateController { mFcConfig.processConstantLocked(properties, key); } - private void registerBroadcastReceiver() { - IntentFilter filter = new IntentFilter(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED); - mContext.registerReceiver(mBroadcastReceiver, filter); - } - - private void unregisterBroadcastReceiver() { - mContext.unregisterReceiver(mBroadcastReceiver); - } - - private void updatePowerAllowlistCache() { - if (mDeviceIdleInternal == null) { - return; - } - - // Don't call out to DeviceIdleController with the lock held. - final String[] allowlistedPkgs = mDeviceIdleInternal.getFullPowerWhitelistExceptIdle(); - final ArraySet<String> changedPkgs = new ArraySet<>(); - synchronized (mLock) { - changedPkgs.addAll(mPowerAllowlistedApps); - mPowerAllowlistedApps.clear(); - for (final String pkgName : allowlistedPkgs) { - mPowerAllowlistedApps.add(pkgName); - if (changedPkgs.contains(pkgName)) { - changedPkgs.remove(pkgName); - } else { - changedPkgs.add(pkgName); - } - } - mPackagesToCheck.addAll(changedPkgs); - mHandler.sendEmptyMessage(MSG_CHECK_PACKAGES); - } - } - @VisibleForTesting class FlexibilityTracker { final ArrayList<ArraySet<JobStatus>> mTrackedJobs; @@ -1343,12 +1302,12 @@ public final class FlexibilityController extends StateController { mFlexibilityEnabled = true; mPrefetchController .registerPrefetchChangedListener(mPrefetchChangedListener); - registerBroadcastReceiver(); + mSpecialAppTracker.startTracking(); } else { mFlexibilityEnabled = false; mPrefetchController .unRegisterPrefetchChangedListener(mPrefetchChangedListener); - unregisterBroadcastReceiver(); + mSpecialAppTracker.stopTracking(); } } break; @@ -1653,6 +1612,176 @@ public final class FlexibilityController extends StateController { return mFcConfig; } + private class SpecialAppTracker { + /** + * Lock for objects inside this class. This should never be held when attempting to acquire + * {@link #mLock}. It is fine to acquire this if already holding {@link #mLock}. + */ + private final Object mSatLock = new Object(); + + private DeviceIdleInternal mDeviceIdleInternal; + + /** Set of all apps that have been deemed special, keyed by user ID. */ + private final SparseSetArray<String> mSpecialApps = new SparseSetArray<>(); + @GuardedBy("mSatLock") + private final ArraySet<String> mPowerAllowlistedApps = new ArraySet<>(); + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + switch (intent.getAction()) { + case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED: + mHandler.post(SpecialAppTracker.this::updatePowerAllowlistCache); + break; + } + } + }; + + public boolean isSpecialApp(final int userId, @NonNull String packageName) { + synchronized (mSatLock) { + if (mSpecialApps.contains(UserHandle.USER_ALL, packageName)) { + return true; + } + if (mSpecialApps.contains(userId, packageName)) { + return true; + } + } + return false; + } + + private boolean isSpecialAppInternal(final int userId, @NonNull String packageName) { + synchronized (mSatLock) { + if (mPowerAllowlistedApps.contains(packageName)) { + return true; + } + } + return false; + } + + private void onAppRemoved(final int userId, String packageName) { + synchronized (mSatLock) { + // Don't touch the USER_ALL set here. If the app is completely removed from the + // device, any list that affects USER_ALL should update and this would eventually + // be updated with those lists no longer containing the app. + mSpecialApps.remove(userId, packageName); + } + } + + private void onSystemServicesReady() { + mDeviceIdleInternal = LocalServices.getService(DeviceIdleInternal.class); + + synchronized (mLock) { + if (mFlexibilityEnabled) { + mHandler.post(SpecialAppTracker.this::updatePowerAllowlistCache); + } + } + } + + private void onUserRemoved(final int userId) { + synchronized (mSatLock) { + mSpecialApps.remove(userId); + } + } + + private void startTracking() { + IntentFilter filter = new IntentFilter( + PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED); + mContext.registerReceiver(mBroadcastReceiver, filter); + + updatePowerAllowlistCache(); + } + + private void stopTracking() { + mContext.unregisterReceiver(mBroadcastReceiver); + + synchronized (mSatLock) { + mPowerAllowlistedApps.clear(); + mSpecialApps.clear(); + } + } + + /** + * Update the processed special app set for the specified user ID, only looking at the + * specified set of apps. This method must <b>NEVER</b> be called while holding + * {@link #mSatLock}. + */ + private void updateSpecialAppSetUnlocked(final int userId, @NonNull ArraySet<String> pkgs) { + // This method may need to acquire mLock, so ensure that mSatLock isn't held to avoid + // lock inversion. + if (Thread.holdsLock(mSatLock)) { + throw new IllegalStateException("Must never hold local mSatLock"); + } + if (pkgs.size() == 0) { + return; + } + final ArraySet<String> changedPkgs = new ArraySet<>(); + + synchronized (mSatLock) { + for (int i = pkgs.size() - 1; i >= 0; --i) { + final String pkgName = pkgs.valueAt(i); + if (isSpecialAppInternal(userId, pkgName)) { + if (mSpecialApps.add(userId, pkgName)) { + changedPkgs.add(pkgName); + } + } else if (mSpecialApps.remove(userId, pkgName)) { + changedPkgs.add(pkgName); + } + } + } + + if (changedPkgs.size() > 0) { + synchronized (mLock) { + mPackagesToCheck.addAll(changedPkgs); + mHandler.sendEmptyMessage(MSG_CHECK_PACKAGES); + } + } + } + + private void updatePowerAllowlistCache() { + if (mDeviceIdleInternal == null) { + return; + } + + // Don't call out to DeviceIdleController with the lock held. + final String[] allowlistedPkgs = mDeviceIdleInternal.getFullPowerWhitelistExceptIdle(); + final ArraySet<String> changedPkgs = new ArraySet<>(); + synchronized (mSatLock) { + changedPkgs.addAll(mPowerAllowlistedApps); + mPowerAllowlistedApps.clear(); + for (String pkgName : allowlistedPkgs) { + mPowerAllowlistedApps.add(pkgName); + if (!changedPkgs.remove(pkgName)) { + // The package wasn't in the previous set of allowlisted apps. Add it + // since its state has changed. + changedPkgs.add(pkgName); + } + } + } + + // The full allowlist is currently user-agnostic, so use USER_ALL for these packages. + updateSpecialAppSetUnlocked(UserHandle.USER_ALL, changedPkgs); + } + + public void dump(@NonNull IndentingPrintWriter pw) { + pw.println("Special apps:"); + pw.increaseIndent(); + + synchronized (mSatLock) { + for (int u = 0; u < mSpecialApps.size(); ++u) { + pw.print(mSpecialApps.keyAt(u)); + pw.print(": "); + pw.println(mSpecialApps.valuesAt(u)); + } + + pw.println(); + pw.print("Power allowlisted packages: "); + pw.println(mPowerAllowlistedApps); + } + + pw.decreaseIndent(); + } + } + @Override @GuardedBy("mLock") public void dumpConstants(IndentingPrintWriter pw) { @@ -1690,8 +1819,7 @@ public final class FlexibilityController extends StateController { pw.decreaseIndent(); pw.println(); - pw.print("Power allowlisted packages: "); - pw.println(mPowerAllowlistedApps); + mSpecialAppTracker.dump(pw); pw.println(); mFlexibilityTracker.dump(pw, predicate, nowElapsed); diff --git a/boot/Android.bp b/boot/Android.bp index cdfa7c80bc93..f60bb9e7149a 100644 --- a/boot/Android.bp +++ b/boot/Android.bp @@ -31,6 +31,7 @@ soong_config_module_type { "car_bootclasspath_fragment", "nfc_apex_bootclasspath_fragment", "release_crashrecovery_module", + "release_package_profiling_module", ], properties: [ "fragments", @@ -122,10 +123,6 @@ custom_platform_bootclasspath { module: "com.android.permission-bootclasspath-fragment", }, { - apex: "com.android.profiling", - module: "com.android.profiling-bootclasspath-fragment", - }, - { apex: "com.android.scheduling", module: "com.android.scheduling-bootclasspath-fragment", }, @@ -179,6 +176,15 @@ custom_platform_bootclasspath { }, ], }, + release_package_profiling_module: { + fragments: [ + // only used if profiling is enabled. + { + apex: "com.android.profiling", + module: "com.android.profiling-bootclasspath-fragment", + }, + ], + }, }, // Additional information needed by hidden api processing. diff --git a/core/api/current.txt b/core/api/current.txt index 386396c67c71..b4c3f44b4ec4 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -203,7 +203,7 @@ package android { field public static final String MANAGE_DEVICE_POLICY_SYSTEM_APPS = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_APPS"; field public static final String MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS"; field public static final String MANAGE_DEVICE_POLICY_SYSTEM_UPDATES = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES"; - field @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") public static final String MANAGE_DEVICE_POLICY_THREAD_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK"; + field @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") public static final String MANAGE_DEVICE_POLICY_THREAD_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK"; field public static final String MANAGE_DEVICE_POLICY_TIME = "android.permission.MANAGE_DEVICE_POLICY_TIME"; field public static final String MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING = "android.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING"; field public static final String MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER = "android.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER"; @@ -691,7 +691,6 @@ package android { field public static final int defaultHeight = 16844021; // 0x10104f5 field @FlaggedApi("android.content.res.default_locale") public static final int defaultLocale; field public static final int defaultToDeviceProtectedStorage = 16844036; // 0x1010504 - field @FlaggedApi("android.nfc.Flags.FLAG_OBSERVE_MODE") public static final int defaultToObserveMode; field public static final int defaultValue = 16843245; // 0x10101ed field public static final int defaultWidth = 16844020; // 0x10104f4 field public static final int delay = 16843212; // 0x10101cc @@ -1501,6 +1500,7 @@ package android { field public static final int shortcutId = 16844072; // 0x1010528 field public static final int shortcutLongLabel = 16844074; // 0x101052a field public static final int shortcutShortLabel = 16844073; // 0x1010529 + field @FlaggedApi("android.nfc.Flags.FLAG_OBSERVE_MODE") public static final int shouldDefaultToObserveMode; field public static final int shouldDisableView = 16843246; // 0x10101ee field public static final int shouldUseDefaultUnfoldTransition = 16844364; // 0x101064c field public static final int showAsAction = 16843481; // 0x10102d9 @@ -3350,7 +3350,6 @@ package android.accessibilityservice { method @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") public void attachAccessibilityOverlayToWindow(int, @NonNull android.view.SurfaceControl, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer); method public boolean clearCache(); method public boolean clearCachedSubtree(@NonNull android.view.accessibility.AccessibilityNodeInfo); - method @FlaggedApi("android.view.accessibility.braille_display_hid") public void clearTestBrailleDisplayController(); method public final void disableSelf(); method public final boolean dispatchGesture(@NonNull android.accessibilityservice.GestureDescription, @Nullable android.accessibilityservice.AccessibilityService.GestureResultCallback, @Nullable android.os.Handler); method public android.view.accessibility.AccessibilityNodeInfo findFocus(int); @@ -3386,7 +3385,6 @@ package android.accessibilityservice { method public boolean setCacheEnabled(boolean); method public void setGestureDetectionPassthroughRegion(int, @NonNull android.graphics.Region); method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo); - method @FlaggedApi("android.view.accessibility.braille_display_hid") public void setTestBrailleDisplayController(@NonNull android.accessibilityservice.BrailleDisplayController); method public void setTouchExplorationPassthroughRegion(int, @NonNull android.graphics.Region); method public void takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull android.accessibilityservice.AccessibilityService.TakeScreenshotCallback); method public void takeScreenshotOfWindow(int, @NonNull java.util.concurrent.Executor, @NonNull android.accessibilityservice.AccessibilityService.TakeScreenshotCallback); @@ -13218,7 +13216,7 @@ package android.content.pm { field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio.access"; field public static final String FEATURE_TELEPHONY_SUBSCRIPTION = "android.hardware.telephony.subscription"; field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television"; - field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network"; + field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network"; field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen"; field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch"; field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct"; @@ -13510,7 +13508,7 @@ package android.content.pm { field public static final int FLAG_USE_APP_ZYGOTE = 8; // 0x8 field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40 field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR, android.Manifest.permission.UWB_RANGING}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10 - field @Deprecated @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1 + field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1 field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100 field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_LOCATION}, anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8 field public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; // 0xffffffff @@ -34086,7 +34084,7 @@ package android.os { field @FlaggedApi("android.app.admin.flags.esim_management_enabled") public static final String DISALLOW_SIM_GLOBALLY = "no_sim_globally"; field public static final String DISALLOW_SMS = "no_sms"; field public static final String DISALLOW_SYSTEM_ERROR_DIALOGS = "no_system_error_dialogs"; - field @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network"; + field @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network"; field public static final String DISALLOW_ULTRA_WIDEBAND_RADIO = "no_ultra_wideband_radio"; field public static final String DISALLOW_UNIFIED_PASSWORD = "no_unified_password"; field public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps"; @@ -35817,54 +35815,6 @@ package android.provider { field public static final String LONGITUDE = "longitude"; } - @FlaggedApi("android.provider.user_keys") public final class ContactKeysManager { - method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.ContactKey> getAllContactKeys(@NonNull String); - method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.SelfKey> getAllSelfKeys(); - method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.ContactKeysManager.ContactKey getContactKey(@NonNull String, @NonNull String, @NonNull String); - method public static int getMaxKeySizeBytes(); - method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.ContactKey> getOwnerContactKeys(@NonNull String); - method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.SelfKey> getOwnerSelfKeys(); - method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.ContactKeysManager.SelfKey getSelfKey(@NonNull String, @NonNull String); - method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeContactKey(@NonNull String, @NonNull String, @NonNull String); - method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeSelfKey(@NonNull String, @NonNull String); - method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, int); - method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int); - method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public void updateOrInsertContactKey(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]); - method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateOrInsertSelfKey(@NonNull String, @NonNull String, @NonNull byte[]); - method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, int); - field public static final int VERIFICATION_STATE_UNVERIFIED = 0; // 0x0 - field public static final int VERIFICATION_STATE_VERIFICATION_FAILED = 1; // 0x1 - field public static final int VERIFICATION_STATE_VERIFIED = 2; // 0x2 - } - - public static final class ContactKeysManager.ContactKey implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public String getAccountId(); - method @Nullable public String getDeviceId(); - method @Nullable public String getDisplayName(); - method @Nullable public String getEmailAddress(); - method @Nullable public byte[] getKeyValue(); - method public int getLocalVerificationState(); - method @NonNull public String getOwnerPackageName(); - method @Nullable public String getPhoneNumber(); - method public int getRemoteVerificationState(); - method public long getTimeUpdated(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.provider.ContactKeysManager.ContactKey> CREATOR; - } - - public static final class ContactKeysManager.SelfKey implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public String getAccountId(); - method @Nullable public String getDeviceId(); - method @Nullable public byte[] getKeyValue(); - method @NonNull public String getOwnerPackageName(); - method public int getRemoteVerificationState(); - method public long getTimeUpdated(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.provider.ContactKeysManager.SelfKey> CREATOR; - } - @Deprecated public class Contacts { field @Deprecated public static final String AUTHORITY = "contacts"; field @Deprecated public static final android.net.Uri CONTENT_URI; @@ -37165,6 +37115,54 @@ package android.provider { method public final int update(android.net.Uri, android.content.ContentValues, String, String[]); } + @FlaggedApi("android.provider.user_keys") public final class E2eeContactKeysManager { + method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.E2eeContactKeysManager.E2eeContactKey> getAllE2eeContactKeys(@NonNull String); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.E2eeContactKeysManager.E2eeSelfKey> getAllE2eeSelfKeys(); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.E2eeContactKeysManager.E2eeContactKey getE2eeContactKey(@NonNull String, @NonNull String, @NonNull String); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.E2eeContactKeysManager.E2eeSelfKey getE2eeSelfKey(@NonNull String, @NonNull String); + method public static int getMaxKeySizeBytes(); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.E2eeContactKeysManager.E2eeContactKey> getOwnerE2eeContactKeys(@NonNull String); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.E2eeContactKeysManager.E2eeSelfKey> getOwnerE2eeSelfKeys(); + method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeE2eeContactKey(@NonNull String, @NonNull String, @NonNull String); + method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeE2eeSelfKey(@NonNull String, @NonNull String); + method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, int); + method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int); + method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, int); + method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public void updateOrInsertE2eeContactKey(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]); + method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateOrInsertE2eeSelfKey(@NonNull String, @NonNull String, @NonNull byte[]); + field public static final int VERIFICATION_STATE_UNVERIFIED = 0; // 0x0 + field public static final int VERIFICATION_STATE_VERIFICATION_FAILED = 1; // 0x1 + field public static final int VERIFICATION_STATE_VERIFIED = 2; // 0x2 + } + + public static final class E2eeContactKeysManager.E2eeContactKey implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public String getAccountId(); + method @Nullable public String getDeviceId(); + method @Nullable public String getDisplayName(); + method @Nullable public String getEmailAddress(); + method @Nullable public byte[] getKeyValue(); + method public int getLocalVerificationState(); + method @NonNull public String getOwnerPackageName(); + method @Nullable public String getPhoneNumber(); + method public int getRemoteVerificationState(); + method public long getTimeUpdated(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.provider.E2eeContactKeysManager.E2eeContactKey> CREATOR; + } + + public static final class E2eeContactKeysManager.E2eeSelfKey implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public String getAccountId(); + method @Nullable public String getDeviceId(); + method @Nullable public byte[] getKeyValue(); + method @NonNull public String getOwnerPackageName(); + method public int getRemoteVerificationState(); + method public long getTimeUpdated(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.provider.E2eeContactKeysManager.E2eeSelfKey> CREATOR; + } + @Deprecated public final class FontRequest { ctor @Deprecated public FontRequest(@NonNull String, @NonNull String, @NonNull String); ctor @Deprecated public FontRequest(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.List<java.util.List<byte[]>>); @@ -39801,6 +39799,7 @@ package android.security.keystore { method @Deprecated public boolean isInsideSecureHardware(); method public boolean isInvalidatedByBiometricEnrollment(); method public boolean isTrustedUserPresenceRequired(); + method @FlaggedApi("android.security.keyinfo_unlocked_device_required") public boolean isUnlockedDeviceRequired(); method public boolean isUserAuthenticationRequired(); method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware(); method public boolean isUserAuthenticationValidWhileOnBody(); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 062bdaad9f7f..1718452548b3 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -327,7 +327,7 @@ package android { field public static final String RECOVER_KEYSTORE = "android.permission.RECOVER_KEYSTORE"; field public static final String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER"; field public static final String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER"; - field @FlaggedApi("com.android.net.flags.register_nsd_offload_engine") public static final String REGISTER_NSD_OFFLOAD_ENGINE = "android.permission.REGISTER_NSD_OFFLOAD_ENGINE"; + field @FlaggedApi("android.net.platform.flags.register_nsd_offload_engine") public static final String REGISTER_NSD_OFFLOAD_ENGINE = "android.permission.REGISTER_NSD_OFFLOAD_ENGINE"; field public static final String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION"; field public static final String REGISTER_STATS_PULL_ATOM = "android.permission.REGISTER_STATS_PULL_ATOM"; field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER"; @@ -388,7 +388,7 @@ package android { field public static final String SYSTEM_APPLICATION_OVERLAY = "android.permission.SYSTEM_APPLICATION_OVERLAY"; field public static final String SYSTEM_CAMERA = "android.permission.SYSTEM_CAMERA"; field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED"; - field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED"; + field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED"; field public static final String TIS_EXTENSION_INTERFACE = "android.permission.TIS_EXTENSION_INTERFACE"; field public static final String TOGGLE_AUTOMOTIVE_PROJECTION = "android.permission.TOGGLE_AUTOMOTIVE_PROJECTION"; field public static final String TRIGGER_LOST_MODE = "android.permission.TRIGGER_LOST_MODE"; @@ -1647,14 +1647,12 @@ package android.app.ambientcontext { method public int getDensityLevel(); method @NonNull public java.time.Instant getEndTime(); method public int getEventType(); - method @FlaggedApi("android.app.ambient_heart_rate") @IntRange(from=0xffffffff) public int getRatePerMinute(); method @NonNull public java.time.Instant getStartTime(); method @NonNull public android.os.PersistableBundle getVendorData(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.ambientcontext.AmbientContextEvent> CREATOR; field public static final int EVENT_BACK_DOUBLE_TAP = 3; // 0x3 field public static final int EVENT_COUGH = 1; // 0x1 - field @FlaggedApi("android.app.ambient_heart_rate") public static final int EVENT_HEART_RATE = 4; // 0x4 field public static final int EVENT_SNORE = 2; // 0x2 field public static final int EVENT_UNKNOWN = 0; // 0x0 field public static final int EVENT_VENDOR_WEARABLE_START = 100000; // 0x186a0 @@ -1665,7 +1663,6 @@ package android.app.ambientcontext { field public static final int LEVEL_MEDIUM_HIGH = 4; // 0x4 field public static final int LEVEL_MEDIUM_LOW = 2; // 0x2 field public static final int LEVEL_UNKNOWN = 0; // 0x0 - field @FlaggedApi("android.app.ambient_heart_rate") public static final int RATE_PER_MINUTE_UNKNOWN = -1; // 0xffffffff } public static final class AmbientContextEvent.Builder { @@ -1675,7 +1672,6 @@ package android.app.ambientcontext { method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setDensityLevel(int); method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setEndTime(@NonNull java.time.Instant); method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setEventType(int); - method @FlaggedApi("android.app.ambient_heart_rate") @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setRatePerMinute(@IntRange(from=0xffffffff) int); method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setStartTime(@NonNull java.time.Instant); method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setVendorData(@NonNull android.os.PersistableBundle); } @@ -3787,7 +3783,7 @@ package android.content { field public static final String SYSTEM_CONFIG_SERVICE = "system_config"; field public static final String SYSTEM_UPDATE_SERVICE = "system_update"; field public static final String TETHERING_SERVICE = "tethering"; - field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network"; + field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network"; field public static final String TIME_MANAGER_SERVICE = "time_manager"; field public static final String TRANSLATION_MANAGER_SERVICE = "translation"; field public static final String UI_TRANSLATION_SERVICE = "ui_translation"; @@ -10421,9 +10417,7 @@ package android.nfc.cardemulation { @FlaggedApi("android.nfc.enable_nfc_mainline") public final class ApduServiceInfo implements android.os.Parcelable { ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public ApduServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo, boolean) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; - method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilter(@NonNull String); - method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilterToAutoTransact(@NonNull String); - method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean defaultToObserveMode(); + method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilter(@NonNull String, boolean); method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents(); method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dump(@NonNull android.os.ParcelFileDescriptor, @NonNull java.io.PrintWriter, @NonNull String[]); method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dumpDebug(@NonNull android.util.proto.ProtoOutputStream); @@ -10453,9 +10447,10 @@ package android.nfc.cardemulation { method @FlaggedApi("android.nfc.enable_nfc_mainline") public boolean requiresUnlock(); method @FlaggedApi("android.nfc.enable_nfc_mainline") public void resetOffHostSecureElement(); method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setCategoryOtherServiceEnabled(boolean); - method @FlaggedApi("android.nfc.nfc_observe_mode") public void setDefaultToObserveMode(boolean); method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setDynamicAidGroup(@NonNull android.nfc.cardemulation.AidGroup); method @FlaggedApi("android.nfc.enable_nfc_mainline") public void setOffHostSecureElement(@NonNull String); + method @FlaggedApi("android.nfc.nfc_observe_mode") public void setShouldDefaultToObserveMode(boolean); + method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean shouldDefaultToObserveMode(); method @FlaggedApi("android.nfc.enable_nfc_mainline") public void writeToParcel(@NonNull android.os.Parcel, int); field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR; } @@ -11709,12 +11704,6 @@ package android.provider { field public static final int ERROR_UNKNOWN = 0; // 0x0 } - @FlaggedApi("android.provider.user_keys") public final class ContactKeysManager { - method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, @NonNull String, int); - method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, @NonNull String, int); - method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int); - } - @Deprecated public static final class ContactsContract.MetadataSync implements android.provider.BaseColumns android.provider.ContactsContract.MetadataSyncColumns { field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata"; field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata"; @@ -11772,6 +11761,12 @@ package android.provider { field public static final int FLAG_REMOVABLE_USB = 524288; // 0x80000 } + @FlaggedApi("android.provider.user_keys") public final class E2eeContactKeysManager { + method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, @NonNull String, int); + method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, @NonNull String, int); + method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int); + } + public abstract class SearchIndexableData { ctor public SearchIndexableData(); ctor public SearchIndexableData(android.content.Context); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index cdf232cd71ee..caddf5aea324 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -251,6 +251,7 @@ package android.app { method @RequiresPermission("android.permission.MANAGE_APPOPS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>); method public static int getNumOps(); method public boolean isOperationActive(int, int, String); + method public int noteOpNoThrow(int, @NonNull android.content.AttributionSource, @Nullable String); method @RequiresPermission("android.permission.MANAGE_APPOPS") public void offsetHistory(long); method public static String opToPermission(int); method public static int permissionToOpCode(String); @@ -316,9 +317,6 @@ package android.app { } public class ComponentOptions { - field public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = 1; // 0x1 - field public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2; // 0x2 - field public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = 0; // 0x0 } public class DownloadManager { @@ -3966,6 +3964,7 @@ package android.view.inputmethod { } public final class InputMethodInfo implements android.os.Parcelable { + ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, @NonNull String, boolean, @NonNull String); ctor @FlaggedApi("android.view.inputmethod.connectionless_handwriting") public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, @NonNull String, boolean, boolean, @NonNull String); ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int); field public static final int COMPONENT_NAME_MAX_LENGTH = 1000; // 0x3e8 diff --git a/core/java/Android.bp b/core/java/Android.bp index 34b8a878b3d1..ab1c9a4ef48d 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -528,14 +528,10 @@ filegroup { ], } -// common protolog sources without classes that rely on Android SDK -filegroup { - name: "protolog-common-no-android-src", +java_library { + name: "protolog-group", srcs: [ - ":protolog-common-src", - ], - exclude_srcs: [ - "com/android/internal/protolog/common/ProtoLog.java", + "com/android/internal/protolog/common/IProtoLogGroup.java", ], } @@ -548,13 +544,20 @@ filegroup { ], } +filegroup { + name: "protolog-impl", + srcs: [ + "com/android/internal/protolog/ProtoLogImpl.java", + ], +} + java_library { name: "protolog-lib", platform_apis: true, srcs: [ "com/android/internal/protolog/ProtoLogImpl.java", "com/android/internal/protolog/ProtoLogViewerConfigReader.java", - ":protolog-common-src", + ":perfetto_trace_javastream_protos", ], } diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 42c32723fd72..d70fa19a4468 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -81,7 +81,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collections; import java.util.List; -import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.function.IntConsumer; @@ -853,7 +852,6 @@ public abstract class AccessibilityService extends Service { private final SparseArray<AccessibilityButtonController> mAccessibilityButtonControllers = new SparseArray<>(0); private BrailleDisplayController mBrailleDisplayController; - private BrailleDisplayController mTestBrailleDisplayController; private int mGestureStatusCallbackSequence; @@ -3650,46 +3648,10 @@ public abstract class AccessibilityService extends Service { public BrailleDisplayController getBrailleDisplayController() { BrailleDisplayController.checkApiFlagIsEnabled(); synchronized (mLock) { - if (mTestBrailleDisplayController != null) { - return mTestBrailleDisplayController; - } - if (mBrailleDisplayController == null) { mBrailleDisplayController = new BrailleDisplayControllerImpl(this, mLock); } return mBrailleDisplayController; } } - - /** - * Set the {@link BrailleDisplayController} implementation that will be returned by - * {@link #getBrailleDisplayController}, to allow this accessibility service to test its - * interaction with BrailleDisplayController without requiring a real Braille display. - * - * <p>For full test fidelity, ensure that this test-only implementation follows the same - * behavior specified in the documentation for {@link BrailleDisplayController}, including - * thrown exceptions. - * - * @param controller A test-only implementation of {@link BrailleDisplayController}. - */ - @FlaggedApi(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID) - public void setTestBrailleDisplayController(@NonNull BrailleDisplayController controller) { - BrailleDisplayController.checkApiFlagIsEnabled(); - Objects.requireNonNull(controller); - synchronized (mLock) { - mTestBrailleDisplayController = controller; - } - } - - /** - * Clears the {@link BrailleDisplayController} previously set by - * {@link #setTestBrailleDisplayController}. - */ - @FlaggedApi(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID) - public void clearTestBrailleDisplayController() { - BrailleDisplayController.checkApiFlagIsEnabled(); - synchronized (mLock) { - mTestBrailleDisplayController = null; - } - } } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 251f82320ae5..57c67be7e625 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1002,6 +1002,9 @@ public class Activity extends ContextThemeWrapper new ActivityManager.TaskDescription(); private int mLastTaskDescriptionHashCode; + @ActivityInfo.ScreenOrientation + private int mLastRequestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSET; + protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused}; @SuppressWarnings("unused") @@ -7530,11 +7533,15 @@ public class Activity extends ContextThemeWrapper * {@link ActivityInfo#screenOrientation ActivityInfo.screenOrientation}. */ public void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) { + if (requestedOrientation == mLastRequestedOrientation) { + return; + } if (mParent == null) { ActivityClient.getInstance().setRequestedOrientation(mToken, requestedOrientation); } else { mParent.setRequestedOrientation(requestedOrientation); } + mLastRequestedOrientation = requestedOrientation; } /** @@ -7548,6 +7555,9 @@ public class Activity extends ContextThemeWrapper */ @ActivityInfo.ScreenOrientation public int getRequestedOrientation() { + if (mLastRequestedOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSET) { + return mLastRequestedOrientation; + } if (mParent == null) { return ActivityClient.getInstance().getRequestedOrientation(mToken); } else { diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 2a2c5f05f122..e094ac61b500 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -93,15 +93,30 @@ public class ActivityOptions extends ComponentOptions { */ public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages"; - /** No explicit value chosen. The system will decide whether to grant privileges. */ - public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = - ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; - /** Allow the {@link PendingIntent} to use the background activity start privileges. */ - public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = - ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; - /** Deny the {@link PendingIntent} to use the background activity start privileges. */ - public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = - ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; + /** Enumeration of background activity start modes. + * + * These define if an app wants to grant it's background activity start privileges to a + * {@link PendingIntent}. + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"MODE_BACKGROUND_ACTIVITY_START_"}, value = { + MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED, + MODE_BACKGROUND_ACTIVITY_START_ALLOWED, + MODE_BACKGROUND_ACTIVITY_START_DENIED}) + public @interface BackgroundActivityStartMode {} + /** + * No explicit value chosen. The system will decide whether to grant privileges. + */ + public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = 0; + /** + * Allow the {@link PendingIntent} to use the background activity start privileges. + */ + public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = 1; + /** + * Deny the {@link PendingIntent} to use the background activity start privileges. + */ + public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2; /** * The package name that created the options. diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index ae556c91ab6d..41151c0dc647 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -211,6 +211,7 @@ import android.view.contentcapture.IContentCaptureOptionsCallback; import android.view.translation.TranslationSpec; import android.view.translation.UiTranslationSpec; import android.webkit.WebView; +import android.window.ActivityWindowInfo; import android.window.ITaskFragmentOrganizer; import android.window.SizeConfigurationBuckets; import android.window.SplashScreen; @@ -603,6 +604,9 @@ public final class ActivityThread extends ClientTransactionHandler boolean hideForNow; Configuration createdConfig; Configuration overrideConfig; + @NonNull + private ActivityWindowInfo mActivityWindowInfo; + // Used for consolidating configs before sending on to Activity. private final Configuration tmpConfig = new Configuration(); // Callback used for updating activity override config and camera compat control state. @@ -670,7 +674,8 @@ public final class ActivityThread extends ClientTransactionHandler List<ReferrerIntent> pendingNewIntents, SceneTransitionInfo sceneTransitionInfo, boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client, IBinder assistToken, IBinder shareableActivityToken, boolean launchedFromBubble, - IBinder taskFragmentToken, IBinder initialCallerInfoAccessToken) { + IBinder taskFragmentToken, IBinder initialCallerInfoAccessToken, + ActivityWindowInfo activityWindowInfo) { this.token = token; this.assistToken = assistToken; this.shareableActivityToken = shareableActivityToken; @@ -691,6 +696,7 @@ public final class ActivityThread extends ClientTransactionHandler mSceneTransitionInfo = sceneTransitionInfo; mLaunchedFromBubble = launchedFromBubble; mTaskFragmentToken = taskFragmentToken; + mActivityWindowInfo = activityWindowInfo; init(); } @@ -711,7 +717,7 @@ public final class ActivityThread extends ClientTransactionHandler } activity.mMainThread.handleActivityConfigurationChanged( ActivityClientRecord.this, overrideConfig, newDisplayId, - false /* alwaysReportChange */); + mActivityWindowInfo, false /* alwaysReportChange */); } @Override @@ -779,6 +785,11 @@ public final class ActivityThread extends ClientTransactionHandler return activity != null && activity.mVisibleFromServer; } + @NonNull + public ActivityWindowInfo getActivityWindowInfo() { + return mActivityWindowInfo; + } + public String toString() { ComponentName componentName = intent != null ? intent.getComponent() : null; return "ActivityRecord{" @@ -5987,9 +5998,11 @@ public final class ActivityThread extends ClientTransactionHandler } @Override - public ActivityClientRecord prepareRelaunchActivity(IBinder token, - List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, - int configChanges, MergedConfiguration config, boolean preserveWindow) { + public ActivityClientRecord prepareRelaunchActivity(@NonNull IBinder token, + @Nullable List<ResultInfo> pendingResults, + @Nullable List<ReferrerIntent> pendingNewIntents, int configChanges, + @NonNull MergedConfiguration config, boolean preserveWindow, + @NonNull ActivityWindowInfo activityWindowInfo) { ActivityClientRecord target = null; boolean scheduleRelaunch = false; @@ -6030,14 +6043,15 @@ public final class ActivityThread extends ClientTransactionHandler target.createdConfig = config.getGlobalConfiguration(); target.overrideConfig = config.getOverrideConfiguration(); target.pendingConfigChanges |= configChanges; + target.mActivityWindowInfo = activityWindowInfo; } return scheduleRelaunch ? target : null; } @Override - public void handleRelaunchActivity(ActivityClientRecord tmp, - PendingTransactionActions pendingActions) { + public void handleRelaunchActivity(@NonNull ActivityClientRecord tmp, + @NonNull PendingTransactionActions pendingActions) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); @@ -6117,7 +6131,8 @@ public final class ActivityThread extends ClientTransactionHandler r.activity.mChangingConfigurations = true; handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents, - pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity"); + pendingActions, tmp.startsNotResumed, tmp.overrideConfig, tmp.mActivityWindowInfo, + "handleRelaunchActivity"); } void scheduleRelaunchActivity(IBinder token) { @@ -6172,7 +6187,8 @@ public final class ActivityThread extends ClientTransactionHandler r.overrideConfig); final ActivityRelaunchItem activityRelaunchItem = ActivityRelaunchItem.obtain( r.token, null /* pendingResults */, null /* pendingIntents */, - 0 /* configChanges */, mergedConfiguration, r.mPreserveWindow); + 0 /* configChanges */, mergedConfiguration, r.mPreserveWindow, + r.getActivityWindowInfo()); // Make sure to match the existing lifecycle state in the end of the transaction. final ActivityLifecycleItem lifecycleRequest = TransactionExecutorHelper.getLifecycleRequestForCurrentState(r); @@ -6183,10 +6199,12 @@ public final class ActivityThread extends ClientTransactionHandler executeTransaction(transaction); } - private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges, - List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents, - PendingTransactionActions pendingActions, boolean startsNotResumed, - Configuration overrideConfig, String reason) { + private void handleRelaunchActivityInner(@NonNull ActivityClientRecord r, int configChanges, + @Nullable List<ResultInfo> pendingResults, + @Nullable List<ReferrerIntent> pendingIntents, + @NonNull PendingTransactionActions pendingActions, boolean startsNotResumed, + @NonNull Configuration overrideConfig, @NonNull ActivityWindowInfo activityWindowInfo, + @NonNull String reason) { // Preserve last used intent, it may be set from Activity#setIntent(). final Intent customIntent = r.activity.mIntent; // Need to ensure state is saved. @@ -6219,6 +6237,7 @@ public final class ActivityThread extends ClientTransactionHandler } r.startsNotResumed = startsNotResumed; r.overrideConfig = overrideConfig; + r.mActivityWindowInfo = activityWindowInfo; handleLaunchActivity(r, pendingActions, mLastReportedDeviceId, customIntent); } @@ -6640,11 +6659,12 @@ public final class ActivityThread extends ClientTransactionHandler /** * Sets the supplied {@code overrideConfig} as pending for the {@code token}. Calling * this method prevents any calls to - * {@link #handleActivityConfigurationChanged(ActivityClientRecord, Configuration, int)} from - * processing any configurations older than {@code overrideConfig}. + * {@link #handleActivityConfigurationChanged(ActivityClientRecord, Configuration, int, + * ActivityWindowInfo)} from processing any configurations older than {@code overrideConfig}. */ @Override - public void updatePendingActivityConfiguration(IBinder token, Configuration overrideConfig) { + public void updatePendingActivityConfiguration(@NonNull IBinder token, + @NonNull Configuration overrideConfig) { synchronized (mPendingOverrideConfigs) { final Configuration pendingOverrideConfig = mPendingOverrideConfigs.get(token); if (pendingOverrideConfig != null @@ -6661,9 +6681,10 @@ public final class ActivityThread extends ClientTransactionHandler } @Override - public void handleActivityConfigurationChanged(ActivityClientRecord r, - @NonNull Configuration overrideConfig, int displayId) { - handleActivityConfigurationChanged(r, overrideConfig, displayId, + public void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r, + @NonNull Configuration overrideConfig, int displayId, + @NonNull ActivityWindowInfo activityWindowInfo) { + handleActivityConfigurationChanged(r, overrideConfig, displayId, activityWindowInfo, // This is the only place that uses alwaysReportChange=true. The entry point should // be from ActivityConfigurationChangeItem or MoveToDisplayItem, so the server side // has confirmed the activity should handle the configuration instead of relaunch. @@ -6681,9 +6702,11 @@ public final class ActivityThread extends ClientTransactionHandler * @param overrideConfig Activity override config. * @param displayId Id of the display where activity was moved to, -1 if there was no move and * value didn't change. + * @param activityWindowInfo the window info of the given activity. */ - void handleActivityConfigurationChanged(ActivityClientRecord r, - @NonNull Configuration overrideConfig, int displayId, boolean alwaysReportChange) { + void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r, + @NonNull Configuration overrideConfig, int displayId, + @NonNull ActivityWindowInfo activityWindowInfo, boolean alwaysReportChange) { synchronized (mPendingOverrideConfigs) { final Configuration pendingOverrideConfig = mPendingOverrideConfigs.get(r.token); if (overrideConfig.isOtherSeqNewer(pendingOverrideConfig)) { @@ -6716,6 +6739,8 @@ public final class ActivityThread extends ClientTransactionHandler // Perform updates. r.overrideConfig = overrideConfig; + r.mActivityWindowInfo = activityWindowInfo; + // TODO(b/287582673): notify on ActivityWindowInfo change final ViewRootImpl viewRoot = r.activity.mDecor != null ? r.activity.mDecor.getViewRootImpl() : null; diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 39900a03e560..2afc78cb90e6 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -7800,7 +7800,7 @@ public class AppOpsManager { } final List<AppOpsManager.PackageOps> result; try { - result = mService.getPackagesForOpsForDevice(opCodes, persistentDeviceId); + result = mService.getPackagesForOpsForDevice(opCodes, persistentDeviceId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -8272,14 +8272,24 @@ public class AppOpsManager { cb = new IAppOpsCallback.Stub() { public void opChanged(int op, int uid, String packageName, String persistentDeviceId) { - if (callback instanceof OnOpChangedInternalListener) { - ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName, - persistentDeviceId); - } - if (sAppOpInfos[op].name != null) { - - callback.onOpChanged(sAppOpInfos[op].name, packageName, - UserHandle.getUserId(uid), persistentDeviceId); + if (Flags.deviceAwarePermissionApisEnabled()) { + if (callback instanceof OnOpChangedInternalListener) { + ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName, + persistentDeviceId); + } + if (sAppOpInfos[op].name != null) { + callback.onOpChanged(sAppOpInfos[op].name, packageName, + UserHandle.getUserId(uid), persistentDeviceId); + } + } else { + if (callback instanceof OnOpChangedInternalListener) { + ((OnOpChangedInternalListener) callback).onOpChanged(op, + packageName); + } + if (sAppOpInfos[op].name != null) { + callback.onOpChanged(sAppOpInfos[op].name, packageName, + UserHandle.getUserId(uid)); + } } } }; @@ -8940,6 +8950,8 @@ public class AppOpsManager { * * @hide */ + @TestApi + @SuppressLint("UnflaggedApi") public int noteOpNoThrow(int op, @NonNull AttributionSource attributionSource, @Nullable String message) { return noteOpNoThrow(op, attributionSource.getUid(), attributionSource.getPackageName(), diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java index f6373d690793..f6ec370478a9 100644 --- a/core/java/android/app/AutomaticZenRule.java +++ b/core/java/android/app/AutomaticZenRule.java @@ -377,6 +377,9 @@ public final class AutomaticZenRule implements Parcelable { * Sets the {@link ZenDeviceEffects} associated to this rule. Device effects specify changes to * the device behavior that should apply while the rule is active, but are not directly related * to suppressing notifications (for example: disabling always-on display). + * + * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule}, + * a {@code null} value here means the previous set of effects is retained. */ @FlaggedApi(Flags.FLAG_MODES_API) public void setDeviceEffects(@Nullable ZenDeviceEffects deviceEffects) { @@ -702,7 +705,15 @@ public final class AutomaticZenRule implements Parcelable { } /** - * Sets the component (service or activity) that owns this rule. + * Sets the component name of the + * {@link android.service.notification.ConditionProviderService} that manages this rule + * (but note that {@link android.service.notification.ConditionProviderService} is + * deprecated in favor of using {@link NotificationManager#setAutomaticZenRuleState} to + * notify the system about the state of your rule). + * + * <p>This is exclusive with {@link #setConfigurationActivity}; rules where a configuration + * activity is set will not use the component set here to determine whether the rule + * should be active. */ public @NonNull Builder setOwner(@Nullable ComponentName owner) { mOwner = owner; @@ -740,6 +751,11 @@ public final class AutomaticZenRule implements Parcelable { * information about this rule and/or allows them to configure it. This is required to be * non-null for rules that are not backed by a * {@link android.service.notification.ConditionProviderService}. + * + * <p>This is exclusive with {@link #setOwner}; rules where a configuration + * activity is set will not use the + * {@link android.service.notification.ConditionProviderService} supplied there to determine + * whether the rule should be active. */ public @NonNull Builder setConfigurationActivity( @Nullable ComponentName configurationActivity) { @@ -749,6 +765,9 @@ public final class AutomaticZenRule implements Parcelable { /** * Sets the zen policy. + * + * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule}, + * a {@code null} value here means the previous policy is retained. */ public @NonNull Builder setZenPolicy(@Nullable ZenPolicy policy) { mPolicy = policy; @@ -759,6 +778,9 @@ public final class AutomaticZenRule implements Parcelable { * Sets the {@link ZenDeviceEffects} associated to this rule. Device effects specify changes * to the device behavior that should apply while the rule is active, but are not directly * related to suppressing notifications (for example: disabling always-on display). + * + * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule}, + * a {@code null} value here means the previous set of effects is retained. */ @NonNull public Builder setDeviceEffects(@Nullable ZenDeviceEffects deviceEffects) { diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java index 1b5b0fc5d917..60d622dd78c6 100644 --- a/core/java/android/app/BroadcastOptions.java +++ b/core/java/android/app/BroadcastOptions.java @@ -16,6 +16,8 @@ package android.app; +import static android.app.ActivityOptions.BackgroundActivityStartMode; + import android.annotation.CurrentTimeMillisLong; import android.annotation.FlaggedApi; import android.annotation.IntDef; @@ -1132,7 +1134,8 @@ public class BroadcastOptions extends ComponentOptions { @SystemApi @NonNull @Override // to narrow down the return type - public BroadcastOptions setPendingIntentBackgroundActivityStartMode(int state) { + public BroadcastOptions setPendingIntentBackgroundActivityStartMode( + @BackgroundActivityStartMode int state) { super.setPendingIntentBackgroundActivityStartMode(state); return this; } diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index b30067491a84..b5b3669c1d80 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -30,6 +30,7 @@ import android.content.res.Configuration; import android.os.IBinder; import android.util.MergedConfiguration; import android.view.SurfaceControl; +import android.window.ActivityWindowInfo; import android.window.SplashScreenView.SplashScreenViewParcelable; import android.window.WindowContext; import android.window.WindowContextInfo; @@ -166,11 +167,12 @@ public abstract class ClientTransactionHandler { /** Set pending activity configuration in case it will be updated by other transaction item. */ public abstract void updatePendingActivityConfiguration(@NonNull IBinder token, - Configuration overrideConfig); + @NonNull Configuration overrideConfig); /** Deliver activity (override) configuration change. */ public abstract void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r, - Configuration overrideConfig, int displayId); + @NonNull Configuration overrideConfig, int displayId, + @NonNull ActivityWindowInfo activityWindowInfo); /** Deliver {@link android.window.WindowContextInfo} change. */ public abstract void handleWindowContextInfoChanged(@NonNull IBinder clientToken, @@ -232,12 +234,15 @@ public abstract class ClientTransactionHandler { * @param config New configuration applied to the activity. * @param preserveWindow Whether the activity should try to reuse the window it created, * including the decor view after the relaunch. + * @param activityWindowInfo Window information about the relaunched Activity. * @return An initialized instance of {@link ActivityThread.ActivityClientRecord} to use during * relaunch, or {@code null} if relaunch cancelled. */ - public abstract ActivityClientRecord prepareRelaunchActivity(IBinder token, - List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, - int configChanges, MergedConfiguration config, boolean preserveWindow); + public abstract ActivityClientRecord prepareRelaunchActivity(@NonNull IBinder token, + @Nullable List<ResultInfo> pendingResults, + @Nullable List<ReferrerIntent> pendingNewIntents, int configChanges, + @NonNull MergedConfiguration config, boolean preserveWindow, + @NonNull ActivityWindowInfo activityWindowInfo); /** * Perform activity relaunch. @@ -245,7 +250,7 @@ public abstract class ClientTransactionHandler { * @param pendingActions Pending actions to be used on later stages of activity transaction. * */ public abstract void handleRelaunchActivity(@NonNull ActivityClientRecord r, - PendingTransactionActions pendingActions); + @NonNull PendingTransactionActions pendingActions); /** * Report that relaunch request was handled. diff --git a/core/java/android/app/ComponentOptions.java b/core/java/android/app/ComponentOptions.java index ce16ddf5c05f..397477d72a9a 100644 --- a/core/java/android/app/ComponentOptions.java +++ b/core/java/android/app/ComponentOptions.java @@ -16,16 +16,17 @@ package android.app; -import android.annotation.IntDef; +import static android.app.ActivityOptions.BackgroundActivityStartMode; +import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; +import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; +import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.TestApi; import android.os.Bundle; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - /** * Base class for {@link ActivityOptions} and {@link BroadcastOptions}. * @hide @@ -56,32 +57,6 @@ public class ComponentOptions { private @Nullable Boolean mPendingIntentBalAllowed = null; private boolean mPendingIntentBalAllowedByPermission = false; - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"MODE_BACKGROUND_ACTIVITY_START_"}, value = { - MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED, - MODE_BACKGROUND_ACTIVITY_START_ALLOWED, - MODE_BACKGROUND_ACTIVITY_START_DENIED}) - public @interface BackgroundActivityStartMode {} - /** - * No explicit value chosen. The system will decide whether to grant privileges. - * @hide - */ - @TestApi - public static final int MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED = 0; - /** - * Allow the {@link PendingIntent} to use the background activity start privileges. - * @hide - */ - @TestApi - public static final int MODE_BACKGROUND_ACTIVITY_START_ALLOWED = 1; - /** - * Deny the {@link PendingIntent} to use the background activity start privileges. - * @hide - */ - @TestApi - public static final int MODE_BACKGROUND_ACTIVITY_START_DENIED = 2; - ComponentOptions() { } diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java index 7e06735791ff..d1e517bbd03c 100644 --- a/core/java/android/app/ForegroundServiceTypePolicy.java +++ b/core/java/android/app/ForegroundServiceTypePolicy.java @@ -62,7 +62,6 @@ import android.content.pm.ServiceInfo.ForegroundServiceType; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; -import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -128,14 +127,10 @@ public abstract class ForegroundServiceTypePolicy { * The FGS type enforcement: * deprecating the {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_DATA_SYNC}. * - * <p>Starting a FGS with this type from apps with targetSdkVersion - * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or later will result in a warning - * in the log. - * * @hide */ @ChangeId - @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + @Disabled @Overridable public static final long FGS_TYPE_DATA_SYNC_DEPRECATION_CHANGE_ID = 255039210L; diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 26f85f723bd9..1129f9dbdfeb 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -7543,6 +7543,7 @@ public class Notification implements Parcelable /** * @hide */ + @SuppressWarnings("HiddenAbstractMethod") public abstract boolean areNotificationsVisiblyDifferent(Style other); /** diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 08c193f06286..d01626e17f2d 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -212,7 +212,7 @@ import android.permission.PermissionControllerManager; import android.permission.PermissionManager; import android.print.IPrintManager; import android.print.PrintManager; -import android.provider.ContactKeysManager; +import android.provider.E2eeContactKeysManager; import android.safetycenter.SafetyCenterFrameworkInitializer; import android.scheduling.SchedulingFrameworkInitializer; import android.security.FileIntegrityManager; @@ -1608,16 +1608,16 @@ public final class SystemServiceRegistry { } }); - registerService(Context.CONTACT_KEYS_SERVICE, ContactKeysManager.class, - new CachedServiceFetcher<ContactKeysManager>() { + registerService(Context.CONTACT_KEYS_SERVICE, E2eeContactKeysManager.class, + new CachedServiceFetcher<E2eeContactKeysManager>() { @Override - public ContactKeysManager createService(ContextImpl ctx) + public E2eeContactKeysManager createService(ContextImpl ctx) throws ServiceNotFoundException { if (!android.provider.Flags.userKeys()) { throw new ServiceNotFoundException( "ContactKeysManager is not supported"); } - return new ContactKeysManager(ctx); + return new E2eeContactKeysManager(ctx); }}); // DO NOT do a flag check like this unless the flag is read-only. diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 83fb393da125..02d694436bfe 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -981,12 +981,12 @@ public class WallpaperManager { /** * <strong> Important note: </strong> * <ul> - * <li>Up to version S, this method requires the + * <li>Up to Android 12, this method requires the * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li> - * <li>Starting in T, directly accessing the wallpaper is not possible anymore, + * <li>Starting in Android 13, directly accessing the wallpaper is not possible anymore, * instead the default system wallpaper is returned - * (some versions of T may throw a {@code SecurityException}).</li> - * <li>From version U, this method should not be used + * (some versions of Android 13 may throw a {@code SecurityException}).</li> + * <li>From Android 14, this method should not be used * and will always throw a {@code SecurityException}.</li> * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} * can still access the real wallpaper on all versions. </li> @@ -1265,12 +1265,12 @@ public class WallpaperManager { /** * <strong> Important note: </strong> * <ul> - * <li>Up to version S, this method requires the + * <li>Up to Android 12, this method requires the * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li> - * <li>Starting in T, directly accessing the wallpaper is not possible anymore, + * <li>Starting in Android 13, directly accessing the wallpaper is not possible anymore, * instead the default system wallpaper is returned - * (some versions of T may throw a {@code SecurityException}).</li> - * <li>From version U, this method should not be used + * (some versions of Android 13 may throw a {@code SecurityException}).</li> + * <li>From Android 14, this method should not be used * and will always throw a {@code SecurityException}.</li> * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} * can still access the real wallpaper on all versions. </li> @@ -1318,12 +1318,12 @@ public class WallpaperManager { /** * <strong> Important note: </strong> * <ul> - * <li>Up to version S, this method requires the + * <li>Up to Android 12, this method requires the * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li> - * <li>Starting in T, directly accessing the wallpaper is not possible anymore, + * <li>Starting in Android 13, directly accessing the wallpaper is not possible anymore, * instead the default wallpaper is returned - * (some versions of T may throw a {@code SecurityException}).</li> - * <li>From version U, this method should not be used + * (some versions of Android 13 may throw a {@code SecurityException}).</li> + * <li>From Android 14, this method should not be used * and will always throw a {@code SecurityException}.</li> * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} * can still access the real wallpaper on all versions. </li> @@ -1677,12 +1677,12 @@ public class WallpaperManager { /** * <strong> Important note: </strong> * <ul> - * <li>Up to version S, this method requires the + * <li>Up to Android 12, this method requires the * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li> - * <li>Starting in T, directly accessing the wallpaper is not possible anymore, + * <li>Starting in Android 13, directly accessing the wallpaper is not possible anymore, * instead the default system wallpaper is returned - * (some versions of T may throw a {@code SecurityException}).</li> - * <li>From version U, this method should not be used + * (some versions of Android 13 may throw a {@code SecurityException}).</li> + * <li>From Android 14, this method should not be used * and will always throw a {@code SecurityException}.</li> * <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} * can still access the real wallpaper on all versions. </li> @@ -1904,14 +1904,14 @@ public class WallpaperManager { * caller doesn't have the appropriate permissions, this returns {@code null}. * * <p> - * Before Android U, this method requires the + * For devices running Android 13 or earlier, this method requires the * {@link android.Manifest.permission#QUERY_ALL_PACKAGES} permission. * </p> * * <p> - * Starting from Android U, in order to use this, apps should declare a {@code <queries>} tag - * with the action {@code "android.service.wallpaper.WallpaperService"}. Otherwise, - * this method will return {@code null} if the caller doesn't otherwise have + * For devices running Android 14 or later, in order to use this, apps should declare a + * {@code <queries>} tag with the action {@code "android.service.wallpaper.WallpaperService"}. + * Otherwise, this method will return {@code null} if the caller doesn't otherwise have * <a href="{@docRoot}training/package-visibility">visibility</a> of the wallpaper package. * </p> */ diff --git a/core/java/android/app/admin/PolicySizeVerifier.java b/core/java/android/app/admin/PolicySizeVerifier.java index d5e8ea4525f3..792ebc6ad297 100644 --- a/core/java/android/app/admin/PolicySizeVerifier.java +++ b/core/java/android/app/admin/PolicySizeVerifier.java @@ -88,6 +88,10 @@ public class PolicySizeVerifier { * Throw if Parcelable contains any string that's too long to be serialized. */ public static void enforceMaxParcelableFieldsLength(Parcelable parcelable) { + // TODO(b/326662716) rework to protect against infinite recursion. + if (true) { + return; + } Class<?> clazz = parcelable.getClass(); Field[] fields = clazz.getDeclaredFields(); diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig index cbd8e5b2ec3e..10954aba955c 100644 --- a/core/java/android/app/admin/flags/flags.aconfig +++ b/core/java/android/app/admin/flags/flags.aconfig @@ -117,6 +117,9 @@ flag { namespace: "enterprise" description: "Exempt the default sms app of the context user for suspension when calling setPersonalAppsSuspended" bug: "309183330" + metadata { + purpose: PURPOSE_BUGFIX + } } flag { diff --git a/core/java/android/app/ambient_context.aconfig b/core/java/android/app/ambient_context.aconfig deleted file mode 100644 index 3f73da216b9f..000000000000 --- a/core/java/android/app/ambient_context.aconfig +++ /dev/null @@ -1,8 +0,0 @@ -package: "android.app" - -flag { - namespace: "biometrics_integration" - name: "ambient_heart_rate" - description: "Feature flag for adding heart rate api to ambient context." - bug: "318309481" -} diff --git a/core/java/android/app/ambientcontext/AmbientContextEvent.java b/core/java/android/app/ambientcontext/AmbientContextEvent.java index 5ab7991c6326..13d959c79cd2 100644 --- a/core/java/android/app/ambientcontext/AmbientContextEvent.java +++ b/core/java/android/app/ambientcontext/AmbientContextEvent.java @@ -16,9 +16,7 @@ package android.app.ambientcontext; -import android.annotation.FlaggedApi; import android.annotation.IntDef; -import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcelable; @@ -70,14 +68,6 @@ public final class AmbientContextEvent implements Parcelable { public static final int EVENT_BACK_DOUBLE_TAP = 3; /** - * The integer indicating a heart rate measurement was done. - * - * @see #getRatePerMinute - */ - @Event @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE) - public static final int EVENT_HEART_RATE = 4; - - /** * Integer indicating the start of wearable vendor defined events that can be detected. * These depend on the vendor implementation. */ @@ -89,19 +79,12 @@ public final class AmbientContextEvent implements Parcelable { */ public static final String KEY_VENDOR_WEARABLE_EVENT_NAME = "wearable_event_name"; - /** - * Default value for {@link #getRatePerMinute}. Indicates that the rate of the event is unknown. - */ - @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE) - public static final int RATE_PER_MINUTE_UNKNOWN = -1; - /** @hide */ @IntDef(prefix = { "EVENT_" }, value = { EVENT_UNKNOWN, EVENT_COUGH, EVENT_SNORE, EVENT_BACK_DOUBLE_TAP, - EVENT_HEART_RATE, EVENT_VENDOR_WEARABLE_START, }) @Retention(RetentionPolicy.SOURCE) @@ -187,16 +170,6 @@ public final class AmbientContextEvent implements Parcelable { return new PersistableBundle(); } - /** - * Rate per minute of the event during the start to end time. - * - * @return the rate per minute, or {@link #RATE_PER_MINUTE_UNKNOWN} if the rate is unknown. - */ - private final @IntRange(from = -1) int mRatePerMinute; - private static int defaultRatePerMinute() { - return RATE_PER_MINUTE_UNKNOWN; - } - // Code below generated by codegen v1.0.23. @@ -206,8 +179,6 @@ public final class AmbientContextEvent implements Parcelable { // // To regenerate run: // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/ambientcontext/AmbientContextEvent.java - // then manually add @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE) back to flagged - // APIs. // // To exclude the generated code from IntelliJ auto-formatting enable (one-time): // Settings > Editor > Code Style > Formatter Control @@ -220,7 +191,6 @@ public final class AmbientContextEvent implements Parcelable { EVENT_COUGH, EVENT_SNORE, EVENT_BACK_DOUBLE_TAP, - EVENT_HEART_RATE, EVENT_VENDOR_WEARABLE_START }) @Retention(RetentionPolicy.SOURCE) @@ -239,8 +209,6 @@ public final class AmbientContextEvent implements Parcelable { return "EVENT_SNORE"; case EVENT_BACK_DOUBLE_TAP: return "EVENT_BACK_DOUBLE_TAP"; - case EVENT_HEART_RATE: - return "EVENT_HEART_RATE"; case EVENT_VENDOR_WEARABLE_START: return "EVENT_VENDOR_WEARABLE_START"; default: return Integer.toHexString(value); @@ -287,8 +255,7 @@ public final class AmbientContextEvent implements Parcelable { @NonNull Instant endTime, @LevelValue int confidenceLevel, @LevelValue int densityLevel, - @NonNull PersistableBundle vendorData, - @IntRange(from = -1) int ratePerMinute) { + @NonNull PersistableBundle vendorData) { this.mEventType = eventType; com.android.internal.util.AnnotationValidations.validate( EventCode.class, null, mEventType); @@ -307,10 +274,6 @@ public final class AmbientContextEvent implements Parcelable { this.mVendorData = vendorData; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mVendorData); - this.mRatePerMinute = ratePerMinute; - com.android.internal.util.AnnotationValidations.validate( - IntRange.class, null, mRatePerMinute, - "from", -1); // onConstructed(); // You can define this method to get a callback } @@ -367,17 +330,6 @@ public final class AmbientContextEvent implements Parcelable { return mVendorData; } - /** - * Rate per minute of the event during the start to end time. - * - * @return the rate per minute, or {@link #RATE_PER_MINUTE_UNKNOWN} if the rate is unknown. - */ - @DataClass.Generated.Member - @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE) - public @IntRange(from = -1) int getRatePerMinute() { - return mRatePerMinute; - } - @Override @DataClass.Generated.Member public String toString() { @@ -390,8 +342,7 @@ public final class AmbientContextEvent implements Parcelable { "endTime = " + mEndTime + ", " + "confidenceLevel = " + mConfidenceLevel + ", " + "densityLevel = " + mDensityLevel + ", " + - "vendorData = " + mVendorData + ", " + - "ratePerMinute = " + mRatePerMinute + + "vendorData = " + mVendorData + " }"; } @@ -429,7 +380,6 @@ public final class AmbientContextEvent implements Parcelable { dest.writeInt(mConfidenceLevel); dest.writeInt(mDensityLevel); dest.writeTypedObject(mVendorData, flags); - dest.writeInt(mRatePerMinute); } @Override @@ -449,7 +399,6 @@ public final class AmbientContextEvent implements Parcelable { int confidenceLevel = in.readInt(); int densityLevel = in.readInt(); PersistableBundle vendorData = (PersistableBundle) in.readTypedObject(PersistableBundle.CREATOR); - int ratePerMinute = in.readInt(); this.mEventType = eventType; com.android.internal.util.AnnotationValidations.validate( @@ -469,10 +418,6 @@ public final class AmbientContextEvent implements Parcelable { this.mVendorData = vendorData; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, mVendorData); - this.mRatePerMinute = ratePerMinute; - com.android.internal.util.AnnotationValidations.validate( - IntRange.class, null, mRatePerMinute, - "from", -1); // onConstructed(); // You can define this method to get a callback } @@ -504,7 +449,6 @@ public final class AmbientContextEvent implements Parcelable { private @LevelValue int mConfidenceLevel; private @LevelValue int mDensityLevel; private @NonNull PersistableBundle mVendorData; - private @IntRange(from = -1) int mRatePerMinute; private long mBuilderFieldsSet = 0L; @@ -581,22 +525,10 @@ public final class AmbientContextEvent implements Parcelable { return this; } - /** - * Rate per minute of the event during the start to end time. - */ - @DataClass.Generated.Member - @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE) - public @NonNull Builder setRatePerMinute(@IntRange(from = -1) int value) { - checkNotUsed(); - mBuilderFieldsSet |= 0x40; - mRatePerMinute = value; - return this; - } - /** Builds the instance. This builder should not be touched after calling this! */ public @NonNull AmbientContextEvent build() { checkNotUsed(); - mBuilderFieldsSet |= 0x80; // Mark builder used + mBuilderFieldsSet |= 0x40; // Mark builder used if ((mBuilderFieldsSet & 0x1) == 0) { mEventType = defaultEventType(); @@ -616,22 +548,18 @@ public final class AmbientContextEvent implements Parcelable { if ((mBuilderFieldsSet & 0x20) == 0) { mVendorData = defaultVendorData(); } - if ((mBuilderFieldsSet & 0x40) == 0) { - mRatePerMinute = defaultRatePerMinute(); - } AmbientContextEvent o = new AmbientContextEvent( mEventType, mStartTime, mEndTime, mConfidenceLevel, mDensityLevel, - mVendorData, - mRatePerMinute); + mVendorData); return o; } private void checkNotUsed() { - if ((mBuilderFieldsSet & 0x80) != 0) { + if ((mBuilderFieldsSet & 0x40) != 0) { throw new IllegalStateException( "This Builder should not be reused. Use a new Builder instance instead"); } @@ -639,10 +567,10 @@ public final class AmbientContextEvent implements Parcelable { } @DataClass.Generated( - time = 1705575046107L, + time = 1709014715064L, codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/app/ambientcontext/AmbientContextEvent.java", - inputSignatures = "public static final int EVENT_UNKNOWN\npublic static final int EVENT_COUGH\npublic static final int EVENT_SNORE\npublic static final int EVENT_BACK_DOUBLE_TAP\npublic static final @android.app.ambientcontext.AmbientContextEvent.Event @android.annotation.FlaggedApi int EVENT_HEART_RATE\npublic static final int EVENT_VENDOR_WEARABLE_START\npublic static final java.lang.String KEY_VENDOR_WEARABLE_EVENT_NAME\npublic static final @android.annotation.FlaggedApi int RATE_PER_MINUTE_UNKNOWN\npublic static final int LEVEL_UNKNOWN\npublic static final int LEVEL_LOW\npublic static final int LEVEL_MEDIUM_LOW\npublic static final int LEVEL_MEDIUM\npublic static final int LEVEL_MEDIUM_HIGH\npublic static final int LEVEL_HIGH\nprivate final @android.app.ambientcontext.AmbientContextEvent.EventCode int mEventType\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mStartTime\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mEndTime\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mConfidenceLevel\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mDensityLevel\nprivate final @android.annotation.NonNull android.os.PersistableBundle mVendorData\nprivate final @android.annotation.IntRange int mRatePerMinute\nprivate static int defaultEventType()\nprivate static @android.annotation.NonNull java.time.Instant defaultStartTime()\nprivate static @android.annotation.NonNull java.time.Instant defaultEndTime()\nprivate static int defaultConfidenceLevel()\nprivate static int defaultDensityLevel()\nprivate static android.os.PersistableBundle defaultVendorData()\nprivate static int defaultRatePerMinute()\nclass AmbientContextEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=false, genHiddenConstDefs=true, genParcelable=true, genToString=true)") + inputSignatures = "public static final int EVENT_UNKNOWN\npublic static final int EVENT_COUGH\npublic static final int EVENT_SNORE\npublic static final int EVENT_BACK_DOUBLE_TAP\npublic static final int EVENT_VENDOR_WEARABLE_START\npublic static final java.lang.String KEY_VENDOR_WEARABLE_EVENT_NAME\npublic static final int LEVEL_UNKNOWN\npublic static final int LEVEL_LOW\npublic static final int LEVEL_MEDIUM_LOW\npublic static final int LEVEL_MEDIUM\npublic static final int LEVEL_MEDIUM_HIGH\npublic static final int LEVEL_HIGH\nprivate final @android.app.ambientcontext.AmbientContextEvent.EventCode int mEventType\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mStartTime\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mEndTime\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mConfidenceLevel\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mDensityLevel\nprivate final @android.annotation.NonNull android.os.PersistableBundle mVendorData\nprivate static int defaultEventType()\nprivate static @android.annotation.NonNull java.time.Instant defaultStartTime()\nprivate static @android.annotation.NonNull java.time.Instant defaultEndTime()\nprivate static int defaultConfidenceLevel()\nprivate static int defaultDensityLevel()\nprivate static android.os.PersistableBundle defaultVendorData()\nclass AmbientContextEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=false, genHiddenConstDefs=true, genParcelable=true, genToString=true)") @Deprecated private void __metadata() {} diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java index bc8fac5fa0ce..48ea846e8d50 100644 --- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java +++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java @@ -29,6 +29,7 @@ import android.content.res.Configuration; import android.os.IBinder; import android.os.Parcel; import android.os.Trace; +import android.window.ActivityWindowInfo; import java.util.Objects; @@ -49,11 +50,13 @@ public class ActivityConfigurationChangeItem extends ActivityTransactionItem { } @Override - public void execute(@NonNull ClientTransactionHandler client, @Nullable ActivityClientRecord r, + public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, @NonNull PendingTransactionActions pendingActions) { // TODO(lifecycler): detect if PIP or multi-window mode changed and report it here. Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged"); - client.handleActivityConfigurationChanged(r, mConfiguration, INVALID_DISPLAY); + client.handleActivityConfigurationChanged(r, mConfiguration, INVALID_DISPLAY, + // TODO(b/287582673): add ActivityWindowInfo + new ActivityWindowInfo()); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java index cbb0ae784f82..6da871a74383 100644 --- a/core/java/android/app/servertransaction/ActivityRelaunchItem.java +++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java @@ -30,6 +30,7 @@ import android.os.Parcel; import android.os.Trace; import android.util.MergedConfiguration; import android.util.Slog; +import android.window.ActivityWindowInfo; import com.android.internal.content.ReferrerIntent; @@ -50,6 +51,7 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { private int mConfigChanges; private MergedConfiguration mConfig; private boolean mPreserveWindow; + private ActivityWindowInfo mActivityWindowInfo; /** * A record that was properly configured for relaunch. Execution will be cancelled if not @@ -64,7 +66,7 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { CompatibilityInfo.applyOverrideScaleIfNeeded(mConfig); } mActivityClientRecord = client.prepareRelaunchActivity(getActivityToken(), mPendingResults, - mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow); + mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow, mActivityWindowInfo); } @Override @@ -101,7 +103,8 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { public static ActivityRelaunchItem obtain(@NonNull IBinder activityToken, @Nullable List<ResultInfo> pendingResults, @Nullable List<ReferrerIntent> pendingNewIntents, int configChanges, - @NonNull MergedConfiguration config, boolean preserveWindow) { + @NonNull MergedConfiguration config, boolean preserveWindow, + @NonNull ActivityWindowInfo activityWindowInfo) { ActivityRelaunchItem instance = ObjectPool.obtain(ActivityRelaunchItem.class); if (instance == null) { instance = new ActivityRelaunchItem(); @@ -113,6 +116,7 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { instance.mConfigChanges = configChanges; instance.mConfig = new MergedConfiguration(config); instance.mPreserveWindow = preserveWindow; + instance.mActivityWindowInfo = new ActivityWindowInfo(activityWindowInfo); return instance; } @@ -126,6 +130,7 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { mConfig = null; mPreserveWindow = false; mActivityClientRecord = null; + mActivityWindowInfo = null; ObjectPool.recycle(this); } @@ -141,6 +146,7 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { dest.writeInt(mConfigChanges); dest.writeTypedObject(mConfig, flags); dest.writeBoolean(mPreserveWindow); + dest.writeTypedObject(mActivityWindowInfo, flags); } /** Read from Parcel. */ @@ -151,6 +157,7 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { mConfigChanges = in.readInt(); mConfig = in.readTypedObject(MergedConfiguration.CREATOR); mPreserveWindow = in.readBoolean(); + mActivityWindowInfo = in.readTypedObject(ActivityWindowInfo.CREATOR); } public static final @NonNull Creator<ActivityRelaunchItem> CREATOR = @@ -176,7 +183,8 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { return Objects.equals(mPendingResults, other.mPendingResults) && Objects.equals(mPendingNewIntents, other.mPendingNewIntents) && mConfigChanges == other.mConfigChanges && Objects.equals(mConfig, other.mConfig) - && mPreserveWindow == other.mPreserveWindow; + && mPreserveWindow == other.mPreserveWindow + && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo); } @Override @@ -188,6 +196,7 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { result = 31 * result + mConfigChanges; result = 31 * result + Objects.hashCode(mConfig); result = 31 * result + (mPreserveWindow ? 1 : 0); + result = 31 * result + Objects.hashCode(mActivityWindowInfo); return result; } @@ -198,6 +207,7 @@ public class ActivityRelaunchItem extends ActivityTransactionItem { + ",pendingNewIntents=" + mPendingNewIntents + ",configChanges=" + mConfigChanges + ",config=" + mConfig - + ",preserveWindow" + mPreserveWindow + "}"; + + ",preserveWindow=" + mPreserveWindow + + ",activityWindowInfo=" + mActivityWindowInfo + "}"; } } diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java index 95f5ad0bd38f..f02cb212276b 100644 --- a/core/java/android/app/servertransaction/LaunchActivityItem.java +++ b/core/java/android/app/servertransaction/LaunchActivityItem.java @@ -42,6 +42,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.PersistableBundle; import android.os.Trace; +import android.window.ActivityWindowInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IVoiceInteractor; @@ -81,6 +82,8 @@ public class LaunchActivityItem extends ClientTransactionItem { private boolean mLaunchedFromBubble; private IBinder mTaskFragmentToken; private IBinder mInitialCallerInfoAccessToken; + private ActivityWindowInfo mActivityWindowInfo; + /** * It is only non-null if the process is the first time to launch activity. It is only an * optimization for quick look up of the interface so the field is ignored for comparison. @@ -107,7 +110,7 @@ public class LaunchActivityItem extends ClientTransactionItem { mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState, mPendingResults, mPendingNewIntents, mSceneTransitionInfo, mIsForward, mProfilerInfo, client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble, - mTaskFragmentToken, mInitialCallerInfoAccessToken); + mTaskFragmentToken, mInitialCallerInfoAccessToken, mActivityWindowInfo); client.handleLaunchActivity(r, pendingActions, mDeviceId, null /* customIntent */); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -141,7 +144,8 @@ public class LaunchActivityItem extends ClientTransactionItem { boolean isForward, @Nullable ProfilerInfo profilerInfo, @NonNull IBinder assistToken, @Nullable IActivityClientController activityClientController, @NonNull IBinder shareableActivityToken, boolean launchedFromBubble, - @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken) { + @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken, + @NonNull ActivityWindowInfo activityWindowInfo) { LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class); if (instance == null) { instance = new LaunchActivityItem(); @@ -156,7 +160,8 @@ public class LaunchActivityItem extends ClientTransactionItem { sceneTransitionInfo, isForward, profilerInfo != null ? new ProfilerInfo(profilerInfo) : null, assistToken, activityClientController, shareableActivityToken, - launchedFromBubble, taskFragmentToken, initialCallerInfoAccessToken); + launchedFromBubble, taskFragmentToken, initialCallerInfoAccessToken, + new ActivityWindowInfo(activityWindowInfo)); return instance; } @@ -171,7 +176,7 @@ public class LaunchActivityItem extends ClientTransactionItem { @Override public void recycle() { setValues(this, null, null, 0, null, null, null, 0, null, null, 0, null, null, null, null, - null, false, null, null, null, null, false, null, null); + null, false, null, null, null, null, false, null, null, null); ObjectPool.recycle(this); } @@ -203,6 +208,7 @@ public class LaunchActivityItem extends ClientTransactionItem { dest.writeBoolean(mLaunchedFromBubble); dest.writeStrongBinder(mTaskFragmentToken); dest.writeStrongBinder(mInitialCallerInfoAccessToken); + dest.writeTypedObject(mActivityWindowInfo, flags); } /** Read from Parcel. */ @@ -223,7 +229,8 @@ public class LaunchActivityItem extends ClientTransactionItem { in.readStrongBinder(), in.readBoolean(), in.readStrongBinder(), - in.readStrongBinder()); + in.readStrongBinder(), + in.readTypedObject(ActivityWindowInfo.CREATOR)); } public static final @NonNull Creator<LaunchActivityItem> CREATOR = new Creator<>() { @@ -264,7 +271,8 @@ public class LaunchActivityItem extends ClientTransactionItem { && Objects.equals(mShareableActivityToken, other.mShareableActivityToken) && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken) && Objects.equals(mInitialCallerInfoAccessToken, - other.mInitialCallerInfoAccessToken); + other.mInitialCallerInfoAccessToken) + && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo); } @Override @@ -289,6 +297,7 @@ public class LaunchActivityItem extends ClientTransactionItem { result = 31 * result + Objects.hashCode(mShareableActivityToken); result = 31 * result + Objects.hashCode(mTaskFragmentToken); result = 31 * result + Objects.hashCode(mInitialCallerInfoAccessToken); + result = 31 * result + Objects.hashCode(mActivityWindowInfo); return result; } @@ -335,7 +344,9 @@ public class LaunchActivityItem extends ClientTransactionItem { + ",sceneTransitionInfo=" + mSceneTransitionInfo + ",profilerInfo=" + mProfilerInfo + ",assistToken=" + mAssistToken - + ",shareableActivityToken=" + mShareableActivityToken + "}"; + + ",shareableActivityToken=" + mShareableActivityToken + + ",activityWindowInfo=" + mActivityWindowInfo + + "}"; } // Using the same method to set and clear values to make sure we don't forget anything @@ -351,7 +362,8 @@ public class LaunchActivityItem extends ClientTransactionItem { @Nullable ProfilerInfo profilerInfo, @Nullable IBinder assistToken, @Nullable IActivityClientController activityClientController, @Nullable IBinder shareableActivityToken, boolean launchedFromBubble, - @Nullable IBinder taskFragmentToken, @Nullable IBinder initialCallerInfoAccessToken) { + @Nullable IBinder taskFragmentToken, @Nullable IBinder initialCallerInfoAccessToken, + @Nullable ActivityWindowInfo activityWindowInfo) { instance.mActivityToken = activityToken; instance.mIntent = intent; instance.mIdent = ident; @@ -375,5 +387,6 @@ public class LaunchActivityItem extends ClientTransactionItem { instance.mLaunchedFromBubble = launchedFromBubble; instance.mTaskFragmentToken = taskFragmentToken; instance.mInitialCallerInfoAccessToken = initialCallerInfoAccessToken; + instance.mActivityWindowInfo = activityWindowInfo; } } diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java index 1353d1679427..0702c4594075 100644 --- a/core/java/android/app/servertransaction/MoveToDisplayItem.java +++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java @@ -28,6 +28,7 @@ import android.content.res.Configuration; import android.os.IBinder; import android.os.Parcel; import android.os.Trace; +import android.window.ActivityWindowInfo; import java.util.Objects; @@ -39,6 +40,7 @@ public class MoveToDisplayItem extends ActivityTransactionItem { private int mTargetDisplayId; private Configuration mConfiguration; + private ActivityWindowInfo mActivityWindowInfo; @Override public void preExecute(@NonNull ClientTransactionHandler client) { @@ -52,7 +54,8 @@ public class MoveToDisplayItem extends ActivityTransactionItem { public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r, @NonNull PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay"); - client.handleActivityConfigurationChanged(r, mConfiguration, mTargetDisplayId); + client.handleActivityConfigurationChanged(r, mConfiguration, mTargetDisplayId, + mActivityWindowInfo); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } @@ -69,7 +72,7 @@ public class MoveToDisplayItem extends ActivityTransactionItem { /** Obtain an instance initialized with provided params. */ @NonNull public static MoveToDisplayItem obtain(@NonNull IBinder activityToken, int targetDisplayId, - @NonNull Configuration configuration) { + @NonNull Configuration configuration, @NonNull ActivityWindowInfo activityWindowInfo) { MoveToDisplayItem instance = ObjectPool.obtain(MoveToDisplayItem.class); if (instance == null) { instance = new MoveToDisplayItem(); @@ -77,6 +80,7 @@ public class MoveToDisplayItem extends ActivityTransactionItem { instance.setActivityToken(activityToken); instance.mTargetDisplayId = targetDisplayId; instance.mConfiguration = new Configuration(configuration); + instance.mActivityWindowInfo = new ActivityWindowInfo(activityWindowInfo); return instance; } @@ -86,6 +90,7 @@ public class MoveToDisplayItem extends ActivityTransactionItem { super.recycle(); mTargetDisplayId = 0; mConfiguration = null; + mActivityWindowInfo = null; ObjectPool.recycle(this); } @@ -97,6 +102,7 @@ public class MoveToDisplayItem extends ActivityTransactionItem { super.writeToParcel(dest, flags); dest.writeInt(mTargetDisplayId); dest.writeTypedObject(mConfiguration, flags); + dest.writeTypedObject(mActivityWindowInfo, flags); } /** Read from Parcel. */ @@ -104,6 +110,7 @@ public class MoveToDisplayItem extends ActivityTransactionItem { super(in); mTargetDisplayId = in.readInt(); mConfiguration = in.readTypedObject(Configuration.CREATOR); + mActivityWindowInfo = in.readTypedObject(ActivityWindowInfo.CREATOR); } public static final @NonNull Creator<MoveToDisplayItem> CREATOR = new Creator<>() { @@ -126,7 +133,8 @@ public class MoveToDisplayItem extends ActivityTransactionItem { } final MoveToDisplayItem other = (MoveToDisplayItem) o; return mTargetDisplayId == other.mTargetDisplayId - && Objects.equals(mConfiguration, other.mConfiguration); + && Objects.equals(mConfiguration, other.mConfiguration) + && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo); } @Override @@ -135,6 +143,7 @@ public class MoveToDisplayItem extends ActivityTransactionItem { result = 31 * result + super.hashCode(); result = 31 * result + mTargetDisplayId; result = 31 * result + mConfiguration.hashCode(); + result = 31 * result + Objects.hashCode(mActivityWindowInfo); return result; } @@ -142,6 +151,7 @@ public class MoveToDisplayItem extends ActivityTransactionItem { public String toString() { return "MoveToDisplayItem{" + super.toString() + ",targetDisplayId=" + mTargetDisplayId - + ",configuration=" + mConfiguration + "}"; + + ",configuration=" + mConfiguration + + ",activityWindowInfo=" + mActivityWindowInfo + "}"; } } diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java index 728c350bfb51..b42133939f28 100644 --- a/core/java/android/content/ClipData.java +++ b/core/java/android/content/ClipData.java @@ -169,6 +169,8 @@ import java.util.List; */ @android.ravenwood.annotation.RavenwoodKeepWholeClass public class ClipData implements Parcelable { + private static final String TAG = "ClipData"; + static final String[] MIMETYPES_TEXT_PLAIN = new String[] { ClipDescription.MIMETYPE_TEXT_PLAIN }; static final String[] MIMETYPES_TEXT_HTML = new String[] { @@ -476,7 +478,6 @@ public class ClipData implements Parcelable { * @return Returns the item's textual representation. */ //BEGIN_INCLUDE(coerceToText) - @android.ravenwood.annotation.RavenwoodThrow public CharSequence coerceToText(Context context) { // If this Item has an explicit textual value, simply return that. CharSequence text = getText(); @@ -484,13 +485,20 @@ public class ClipData implements Parcelable { return text; } + // Gracefully handle cases where resolver isn't available + ContentResolver resolver = null; + try { + resolver = context.getContentResolver(); + } catch (Exception e) { + Log.w(TAG, "Failed to obtain ContentResolver: " + e); + } + // If this Item has a URI value, try using that. Uri uri = getUri(); - if (uri != null) { + if (uri != null && resolver != null) { // First see if the URI can be opened as a plain text stream // (of any sub-type). If so, this is the best textual // representation for it. - final ContentResolver resolver = context.getContentResolver(); AssetFileDescriptor descr = null; FileInputStream stream = null; InputStreamReader reader = null; @@ -499,7 +507,7 @@ public class ClipData implements Parcelable { // Ask for a stream of the desired type. descr = resolver.openTypedAssetFileDescriptor(uri, "text/*", null); } catch (SecurityException e) { - Log.w("ClipData", "Failure opening stream", e); + Log.w(TAG, "Failure opening stream", e); } catch (FileNotFoundException|RuntimeException e) { // Unable to open content URI as text... not really an // error, just something to ignore. @@ -519,7 +527,7 @@ public class ClipData implements Parcelable { return builder.toString(); } catch (IOException e) { // Something bad has happened. - Log.w("ClipData", "Failure loading text", e); + Log.w(TAG, "Failure loading text", e); return e.toString(); } } @@ -528,7 +536,8 @@ public class ClipData implements Parcelable { IoUtils.closeQuietly(stream); IoUtils.closeQuietly(reader); } - + } + if (uri != null) { // If we couldn't open the URI as a stream, use the URI itself as a textual // representation (but not for "content", "android.resource" or "file" schemes). final String scheme = uri.getScheme(); @@ -704,7 +713,7 @@ public class ClipData implements Parcelable { } } catch (SecurityException e) { - Log.w("ClipData", "Failure opening stream", e); + Log.w(TAG, "Failure opening stream", e); } catch (FileNotFoundException e) { // Unable to open content URI as text... not really an @@ -712,7 +721,7 @@ public class ClipData implements Parcelable { } catch (IOException e) { // Something bad has happened. - Log.w("ClipData", "Failure loading text", e); + Log.w(TAG, "Failure loading text", e); return Html.escapeHtml(e.toString()); } finally { @@ -1123,7 +1132,7 @@ public class ClipData implements Parcelable { * * @hide */ - @android.ravenwood.annotation.RavenwoodThrow + @android.ravenwood.annotation.RavenwoodKeep public void prepareToLeaveProcess(boolean leavingPackage) { // Assume that callers are going to be granting permissions prepareToLeaveProcess(leavingPackage, Intent.FLAG_GRANT_READ_URI_PERMISSION); @@ -1134,7 +1143,7 @@ public class ClipData implements Parcelable { * * @hide */ - @android.ravenwood.annotation.RavenwoodThrow + @android.ravenwood.annotation.RavenwoodReplace public void prepareToLeaveProcess(boolean leavingPackage, int intentFlags) { final int size = mItems.size(); for (int i = 0; i < size; i++) { @@ -1154,6 +1163,11 @@ public class ClipData implements Parcelable { } } + /** @hide */ + public void prepareToLeaveProcess$ravenwood(boolean leavingPackage, int intentFlags) { + // No process boundaries on Ravenwood; ignored + } + /** {@hide} */ @android.ravenwood.annotation.RavenwoodThrow public void prepareToEnterProcess(AttributionSource source) { diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java index 107f1078b11e..2fabcbae9bbb 100644 --- a/core/java/android/content/ClipboardManager.java +++ b/core/java/android/content/ClipboardManager.java @@ -50,6 +50,7 @@ import java.util.Objects; * </div> */ @SystemService(Context.CLIPBOARD_SERVICE) +@android.ravenwood.annotation.RavenwoodKeepWholeClass public class ClipboardManager extends android.text.ClipboardManager { /** @@ -143,6 +144,7 @@ public class ClipboardManager extends android.text.ClipboardManager { */ @SystemApi @RequiresPermission(Manifest.permission.MANAGE_CLIPBOARD_ACCESS_NOTIFICATION) + @android.ravenwood.annotation.RavenwoodThrow public boolean areClipboardAccessNotificationsEnabled() { try { return mService.areClipboardAccessNotificationsEnabledForUser(mContext.getUserId()); @@ -159,6 +161,7 @@ public class ClipboardManager extends android.text.ClipboardManager { */ @SystemApi @RequiresPermission(Manifest.permission.MANAGE_CLIPBOARD_ACCESS_NOTIFICATION) + @android.ravenwood.annotation.RavenwoodThrow public void setClipboardAccessNotificationsEnabled(boolean enable) { try { mService.setClipboardAccessNotificationsEnabledForUser(enable, mContext.getUserId()); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index f77ebc148070..70d2c7a3a41a 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -83,6 +83,7 @@ import android.os.StatFs; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; +import android.provider.E2eeContactKeysManager; import android.provider.MediaStore; import android.telephony.TelephonyRegistryManager; import android.util.AttributeSet; @@ -4815,9 +4816,7 @@ public abstract class Context { * @see android.net.thread.ThreadNetworkManager * @hide */ - // TODO (b/325886480): update the flag to - // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM" - @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") + @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM) @SystemApi public static final String THREAD_NETWORK_SERVICE = "thread_network"; @@ -6566,10 +6565,10 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve a - * {@link android.provider.ContactKeysManager} to managing contact keys. + * {@link E2eeContactKeysManager} to managing contact keys. * * @see #getSystemService(String) - * @see android.provider.ContactKeysManager + * @see E2eeContactKeysManager */ @FlaggedApi(android.provider.Flags.FLAG_USER_KEYS) public static final String CONTACT_KEYS_SERVICE = "contact_keys"; diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 7a015cd187ca..240cff34ef36 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3974,9 +3974,7 @@ public abstract class PackageManager { * The device is capable of communicating with other devices via * <a href="https://www.threadgroup.org">Thread</a> networking protocol. */ - // TODO (b/325886480): update the flag to - // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM" - @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") + @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM) @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network"; diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java index 9c6aab4bc9fb..5b0cee75e591 100644 --- a/core/java/android/content/pm/ServiceInfo.java +++ b/core/java/android/content/pm/ServiceInfo.java @@ -163,25 +163,12 @@ public class ServiceInfo extends ComponentInfo * Because of this, developers must make sure to stop the foreground service even if * {@link android.app.Service#onTimeout(int, int)} is not called on such versions. * - * <p>Apps targeting API level {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} and - * later should <b>NOT</b> use this type: calling - * {@link android.app.Service#startForeground(int, android.app.Notification, int)} with - * this type on devices running {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} is - * still allowed, but it may throw an {@link android.app.InvalidForegroundServiceTypeException} - * in future platform releases. - * - * <p class="note"> - * Use the {@link android.app.job.JobInfo.Builder#setUserInitiated(boolean)} API for - * user-initiated, network data transfers. - * - * @deprecated Use {@link android.app.job.JobInfo.Builder} APIs or alternate FGS types - * (like {@link #FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING}) applicable to your use-case. + * @see android.app.Service#onTimeout(int, int) */ @RequiresPermission( value = Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional = true ) - @Deprecated public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1 << 0; /** diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig index 22e233aebf36..ac80561c3b50 100644 --- a/core/java/android/content/pm/multiuser.aconfig +++ b/core/java/android/content/pm/multiuser.aconfig @@ -177,3 +177,10 @@ flag { description: "Enable the sensitive notifications toggle to be visible in the Private space settings page" bug: "317067050" } + +flag { + name: "enable_private_space_intent_redirection" + namespace: "profile_experiences" + description: "Enable Private Space telephony and SMS intent redirection to the main user" + bug: "325576602" +} diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java index 6e53fd99873b..3d8ccaaa45cc 100644 --- a/core/java/android/credentials/GetCandidateCredentialsResponse.java +++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java @@ -18,7 +18,7 @@ package android.credentials; import android.annotation.Hide; import android.annotation.NonNull; -import android.app.PendingIntent; +import android.content.Intent; import android.credentials.selection.GetCredentialProviderData; import android.os.Parcel; import android.os.Parcelable; @@ -39,32 +39,22 @@ public final class GetCandidateCredentialsResponse implements Parcelable { @NonNull private final List<GetCredentialProviderData> mCandidateProviderDataList; - private final PendingIntent mPendingIntent; - - /** - * @hide - */ - @Hide - public GetCandidateCredentialsResponse( - GetCredentialResponse getCredentialResponse - ) { - mCandidateProviderDataList = null; - mPendingIntent = null; - } + @NonNull + private final Intent mIntent; /** * @hide */ @Hide public GetCandidateCredentialsResponse( - List<GetCredentialProviderData> candidateProviderDataList, - PendingIntent pendingIntent + @NonNull List<GetCredentialProviderData> candidateProviderDataList, + @NonNull Intent intent ) { Preconditions.checkCollectionNotEmpty( candidateProviderDataList, /*valueName=*/ "candidateProviderDataList"); mCandidateProviderDataList = new ArrayList<>(candidateProviderDataList); - mPendingIntent = pendingIntent; + mIntent = intent; } /** @@ -81,8 +71,9 @@ public final class GetCandidateCredentialsResponse implements Parcelable { * * @hide */ - public PendingIntent getPendingIntent() { - return mPendingIntent; + @NonNull + public Intent getIntent() { + return mIntent; } protected GetCandidateCredentialsResponse(Parcel in) { @@ -91,14 +82,13 @@ public final class GetCandidateCredentialsResponse implements Parcelable { mCandidateProviderDataList = candidateProviderDataList; AnnotationValidations.validate(NonNull.class, null, mCandidateProviderDataList); - - mPendingIntent = in.readTypedObject(PendingIntent.CREATOR); + mIntent = in.readTypedObject(Intent.CREATOR); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeTypedList(mCandidateProviderDataList); - dest.writeTypedObject(mPendingIntent, flags); + dest.writeTypedObject(mIntent, flags); } @Override diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 5dfeac7fca9b..d683d72f17be 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -40,15 +40,12 @@ import android.os.Looper; import android.os.OperationCanceledException; import android.os.SystemProperties; import android.text.TextUtils; -import android.util.ArrayMap; import android.util.ArraySet; import android.util.EventLog; import android.util.Log; import android.util.Pair; import android.util.Printer; -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import dalvik.annotation.optimization.NeverCompile; @@ -106,14 +103,8 @@ public final class SQLiteDatabase extends SQLiteClosable { // Stores reference to all databases opened in the current process. // (The referent Object is not used at this time.) // INVARIANT: Guarded by sActiveDatabases. - @GuardedBy("sActiveDatabases") private static WeakHashMap<SQLiteDatabase, Object> sActiveDatabases = new WeakHashMap<>(); - // Tracks which database files are currently open. If a database file is opened more than - // once at any given moment, the associated databases are marked as "concurrent". - @GuardedBy("sActiveDatabases") - private static final OpenTracker sOpenTracker = new OpenTracker(); - // Thread-local for database sessions that belong to this database. // Each thread has its own database session. // INVARIANT: Immutable. @@ -519,7 +510,6 @@ public final class SQLiteDatabase extends SQLiteClosable { private void dispose(boolean finalized) { final SQLiteConnectionPool pool; - final String path; synchronized (mLock) { if (mCloseGuardLocked != null) { if (finalized) { @@ -530,12 +520,10 @@ public final class SQLiteDatabase extends SQLiteClosable { pool = mConnectionPoolLocked; mConnectionPoolLocked = null; - path = isInMemoryDatabase() ? null : getPath(); } if (!finalized) { synchronized (sActiveDatabases) { - sOpenTracker.close(path); sActiveDatabases.remove(this); } @@ -1144,74 +1132,6 @@ public final class SQLiteDatabase extends SQLiteClosable { } } - /** - * Track the number of times a database file has been opened. There is a primary connection - * associated with every open database, and these can contend with each other, leading to - * unexpected SQLiteDatabaseLockedException exceptions. The tracking here is only advisory: - * multiply-opened databases are logged but no other action is taken. - * - * This class is not thread-safe. - */ - private static class OpenTracker { - // The list of currently-open databases. This maps the database file to the number of - // currently-active opens. - private final ArrayMap<String, Integer> mOpens = new ArrayMap<>(); - - // The maximum number of concurrently open database paths that will be stored. Once this - // many paths have been recorded, further paths are logged but not saved. - private static final int MAX_RECORDED_PATHS = 20; - - // The list of databases that were ever concurrently opened. - private final ArraySet<String> mConcurrent = new ArraySet<>(); - - /** Return the canonical path. On error, just return the input path. */ - private static String normalize(String path) { - try { - return new File(path).toPath().toRealPath().toString(); - } catch (Exception e) { - // If there is an IO or security exception, just continue, using the input path. - return path; - } - } - - /** Return true if the path is currently open in another SQLiteDatabase instance. */ - void open(@Nullable String path) { - if (path == null) return; - path = normalize(path); - - Integer count = mOpens.get(path); - if (count == null || count == 0) { - mOpens.put(path, 1); - return; - } else { - mOpens.put(path, count + 1); - if (mConcurrent.size() < MAX_RECORDED_PATHS) { - mConcurrent.add(path); - } - Log.w(TAG, "multiple primary connections on " + path); - return; - } - } - - void close(@Nullable String path) { - if (path == null) return; - path = normalize(path); - Integer count = mOpens.get(path); - if (count == null || count <= 0) { - Log.e(TAG, "open database counting failure on " + path); - } else if (count == 1) { - // Implicitly set the count to zero, and make mOpens smaller. - mOpens.remove(path); - } else { - mOpens.put(path, count - 1); - } - } - - ArraySet<String> getConcurrentDatabasePaths() { - return new ArraySet<>(mConcurrent); - } - } - private void open() { try { try { @@ -1233,17 +1153,14 @@ public final class SQLiteDatabase extends SQLiteClosable { } private void openInner() { - final String path; synchronized (mLock) { assert mConnectionPoolLocked == null; mConnectionPoolLocked = SQLiteConnectionPool.open(mConfigurationLocked); mCloseGuardLocked.open("close"); - path = isInMemoryDatabase() ? null : getPath(); } synchronized (sActiveDatabases) { sActiveDatabases.put(this, null); - sOpenTracker.open(path); } } @@ -2428,17 +2345,6 @@ public final class SQLiteDatabase extends SQLiteClosable { } /** - * Return list of databases that have been concurrently opened. - * @hide - */ - @VisibleForTesting - public static ArraySet<String> getConcurrentDatabasePaths() { - synchronized (sActiveDatabases) { - return sOpenTracker.getConcurrentDatabasePaths(); - } - } - - /** * Returns true if the new version code is greater than the current database version. * * @param newVersion The new version code. @@ -2860,19 +2766,6 @@ public final class SQLiteDatabase extends SQLiteClosable { dumpDatabaseDirectory(printer, new File(dir), isSystem); } } - - // Dump concurrently-opened database files, if any - final ArraySet<String> concurrent; - synchronized (sActiveDatabases) { - concurrent = sOpenTracker.getConcurrentDatabasePaths(); - } - if (concurrent.size() > 0) { - printer.println(""); - printer.println("Concurrently opened database files"); - for (String f : concurrent) { - printer.println(" " + f); - } - } } private static void dumpDatabaseDirectory(Printer pw, File dir, boolean isSystem) { diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java index 510b14e7acd4..e28f34528f42 100644 --- a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java +++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java @@ -99,7 +99,11 @@ public final class NavigationBarView extends FrameLayout { mDeadZone = new android.inputmethodservice.navigationbar.DeadZone(this); - getImeSwitchButton().setOnClickListener(view -> view.getContext() + getBackButton().setLongClickable(false); + + final ButtonDispatcher imeSwitchButton = getImeSwitchButton(); + imeSwitchButton.setLongClickable(false); + imeSwitchButton.setOnClickListener(view -> view.getContext() .getSystemService(InputMethodManager.class).showInputMethodPicker()); } diff --git a/core/java/android/net/flags.aconfig b/core/java/android/net/flags.aconfig index 6efb87225183..9f9aef8acc6a 100644 --- a/core/java/android/net/flags.aconfig +++ b/core/java/android/net/flags.aconfig @@ -17,3 +17,9 @@ flag { bug: "307898240" } +flag { + name: "register_nsd_offload_engine" + namespace: "android_core_networking" + description: "Flag for registerOffloadEngine API in NsdManager" + bug: "294777050" +} diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java index 36730cb07344..f852d3cd69b2 100644 --- a/core/java/android/os/HandlerThread.java +++ b/core/java/android/os/HandlerThread.java @@ -19,6 +19,8 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; +import java.util.concurrent.Executor; + /** * A {@link Thread} that has a {@link Looper}. * The {@link Looper} can then be used to create {@link Handler}s. @@ -30,7 +32,8 @@ public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; - private @Nullable Handler mHandler; + private volatile @Nullable Handler mHandler; + private volatile @Nullable Executor mExecutor; public HandlerThread(String name) { super(name); @@ -131,6 +134,18 @@ public class HandlerThread extends Thread { } /** + * @return a shared {@link Executor} associated with this thread + * @hide + */ + @NonNull + public Executor getThreadExecutor() { + if (mExecutor == null) { + mExecutor = new HandlerExecutor(getThreadHandler()); + } + return mExecutor; + } + + /** * Quits the handler thread's looper. * <p> * Causes the handler thread's looper to terminate without processing any diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index be17d7c0f0db..ccb534eb1019 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1920,9 +1920,7 @@ public class UserManager { * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ - // TODO (b/325886480): update the flag to - // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_USER_RESTRICTION_ENABLED" - @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") + @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_USER_RESTRICTION_ENABLED) public static final String DISALLOW_THREAD_NETWORK = "no_thread_network"; /** diff --git a/core/java/android/os/WakeLockStats.java b/core/java/android/os/WakeLockStats.java index 69e70a0a8b07..3769f38a9fbf 100644 --- a/core/java/android/os/WakeLockStats.java +++ b/core/java/android/os/WakeLockStats.java @@ -23,17 +23,21 @@ import java.util.List; /** * Snapshot of wake lock stats. - * @hide + * + * @hide */ @android.ravenwood.annotation.RavenwoodKeepWholeClass public final class WakeLockStats implements Parcelable { - /** @hide */ - public static class WakeLock { - public final int uid; - @NonNull - public final String name; + public static class WakeLockData { + + public static final WakeLockData EMPTY = new WakeLockData( + /* timesAcquired= */ 0, /* totalTimeHeldMs= */ 0, /* timeHeldMs= */ 0); + + /** How many times this wakelock has been acquired. */ public final int timesAcquired; + + /** Time in milliseconds that the lock has been held in total. */ public final long totalTimeHeldMs; /** @@ -41,26 +45,34 @@ public final class WakeLockStats implements Parcelable { */ public final long timeHeldMs; - public WakeLock(int uid, @NonNull String name, int timesAcquired, long totalTimeHeldMs, - long timeHeldMs) { - this.uid = uid; - this.name = name; + public WakeLockData(int timesAcquired, long totalTimeHeldMs, long timeHeldMs) { this.timesAcquired = timesAcquired; this.totalTimeHeldMs = totalTimeHeldMs; this.timeHeldMs = timeHeldMs; } - private WakeLock(Parcel in) { - uid = in.readInt(); - name = in.readString(); + /** + * Whether the fields are able to construct a valid wakelock. + */ + public boolean isDataValid() { + final boolean isDataReasonable = timesAcquired > 0 + && totalTimeHeldMs > 0 + && timeHeldMs >= 0 + && totalTimeHeldMs >= timeHeldMs; + return isEmpty() || isDataReasonable; + } + + private boolean isEmpty() { + return timesAcquired == 0 && totalTimeHeldMs == 0 && timeHeldMs == 0; + } + + private WakeLockData(Parcel in) { timesAcquired = in.readInt(); totalTimeHeldMs = in.readLong(); timeHeldMs = in.readLong(); } private void writeToParcel(Parcel out) { - out.writeInt(uid); - out.writeString(name); out.writeInt(timesAcquired); out.writeLong(totalTimeHeldMs); out.writeLong(timeHeldMs); @@ -68,21 +80,98 @@ public final class WakeLockStats implements Parcelable { @Override public String toString() { + return "WakeLockData{" + + "timesAcquired=" + + timesAcquired + + ", totalTimeHeldMs=" + + totalTimeHeldMs + + ", timeHeldMs=" + + timeHeldMs + + "}"; + } + } + + /** @hide */ + public static class WakeLock { + + public static final String NAME_AGGREGATED = "wakelockstats_aggregated"; + + public final int uid; + @NonNull public final String name; + public final boolean isAggregated; + + /** Wakelock data on both foreground and background. */ + @NonNull public final WakeLockData totalWakeLockData; + + /** Wakelock data on background. */ + @NonNull public final WakeLockData backgroundWakeLockData; + + public WakeLock( + int uid, + @NonNull String name, + boolean isAggregated, + @NonNull WakeLockData totalWakeLockData, + @NonNull WakeLockData backgroundWakeLockData) { + this.uid = uid; + this.name = name; + this.isAggregated = isAggregated; + this.totalWakeLockData = totalWakeLockData; + this.backgroundWakeLockData = backgroundWakeLockData; + } + + /** Whether the combination of total and background wakelock data is invalid. */ + public static boolean isDataValid( + WakeLockData totalWakeLockData, WakeLockData backgroundWakeLockData) { + return totalWakeLockData.totalTimeHeldMs > 0 + && totalWakeLockData.isDataValid() + && backgroundWakeLockData.isDataValid() + && totalWakeLockData.timesAcquired >= backgroundWakeLockData.timesAcquired + && totalWakeLockData.totalTimeHeldMs >= backgroundWakeLockData.totalTimeHeldMs + && totalWakeLockData.timeHeldMs >= backgroundWakeLockData.timeHeldMs; + } + + private WakeLock(Parcel in) { + uid = in.readInt(); + name = in.readString(); + isAggregated = in.readBoolean(); + totalWakeLockData = new WakeLockData(in); + backgroundWakeLockData = new WakeLockData(in); + } + + private void writeToParcel(Parcel out) { + out.writeInt(uid); + out.writeString(name); + out.writeBoolean(isAggregated); + totalWakeLockData.writeToParcel(out); + backgroundWakeLockData.writeToParcel(out); + } + + @Override + public String toString() { return "WakeLock{" - + "uid=" + uid - + ", name='" + name + '\'' - + ", timesAcquired=" + timesAcquired - + ", totalTimeHeldMs=" + totalTimeHeldMs - + ", timeHeldMs=" + timeHeldMs - + '}'; + + "uid=" + + uid + + ", name='" + + name + + '\'' + + ", isAggregated=" + + isAggregated + + ", totalWakeLockData=" + + totalWakeLockData + + ", backgroundWakeLockData=" + + backgroundWakeLockData + + '}'; } } private final List<WakeLock> mWakeLocks; + private final List<WakeLock> mAggregatedWakeLocks; - /** @hide **/ - public WakeLockStats(@NonNull List<WakeLock> wakeLocks) { + /** @hide */ + public WakeLockStats( + @NonNull List<WakeLock> wakeLocks, @NonNull List<WakeLock> aggregatedWakeLocks) { mWakeLocks = wakeLocks; + mAggregatedWakeLocks = aggregatedWakeLocks; } @NonNull @@ -90,22 +179,38 @@ public final class WakeLockStats implements Parcelable { return mWakeLocks; } + @NonNull + public List<WakeLock> getAggregatedWakeLocks() { + return mAggregatedWakeLocks; + } + private WakeLockStats(Parcel in) { - final int size = in.readInt(); - mWakeLocks = new ArrayList<>(size); - for (int i = 0; i < size; i++) { + final int wakelockSize = in.readInt(); + mWakeLocks = new ArrayList<>(wakelockSize); + for (int i = 0; i < wakelockSize; i++) { mWakeLocks.add(new WakeLock(in)); } + final int aggregatedWakelockSize = in.readInt(); + mAggregatedWakeLocks = new ArrayList<>(aggregatedWakelockSize); + for (int i = 0; i < aggregatedWakelockSize; i++) { + mAggregatedWakeLocks.add(new WakeLock(in)); + } } @Override public void writeToParcel(@NonNull Parcel out, int flags) { - final int size = mWakeLocks.size(); - out.writeInt(size); - for (int i = 0; i < size; i++) { + final int wakelockSize = mWakeLocks.size(); + out.writeInt(wakelockSize); + for (int i = 0; i < wakelockSize; i++) { WakeLock stats = mWakeLocks.get(i); stats.writeToParcel(out); } + final int aggregatedWakelockSize = mAggregatedWakeLocks.size(); + out.writeInt(aggregatedWakelockSize); + for (int i = 0; i < aggregatedWakelockSize; i++) { + WakeLock stats = mAggregatedWakeLocks.get(i); + stats.writeToParcel(out); + } } @NonNull @@ -127,6 +232,13 @@ public final class WakeLockStats implements Parcelable { @Override public String toString() { - return "WakeLockStats " + mWakeLocks; + return "WakeLockStats{" + + "mWakeLocks: [" + + mWakeLocks + + "]" + + ", mAggregatedWakeLocks: [" + + mAggregatedWakeLocks + + "]" + + '}'; } } diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS index 2cb16d337bba..c21895a2407c 100644 --- a/core/java/android/os/storage/OWNERS +++ b/core/java/android/os/storage/OWNERS @@ -3,11 +3,15 @@ # PLEASE ASSIGN NEW BUGS TO android-storage-triage@, NOT TO INDIVIDUAL PEOPLE # Android Storage Team +aibra@google.com +akgaurav@google.com alukin@google.com ankitavyas@google.com dipankarb@google.com gargshivam@google.com +ishneet@google.com krishang@google.com +oeissa@google.com riyaghai@google.com sahanas@google.com shikhamalhotra@google.com diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java index 460b4dd9b86c..141ffc9a491a 100644 --- a/core/java/android/permission/PermissionUsageHelper.java +++ b/core/java/android/permission/PermissionUsageHelper.java @@ -359,8 +359,7 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis new PermissionGroupUsage(usage.packageName, usage.uid, usage.lastAccessTime, permGroup, usage.isRunning, isPhone, usage.attributionTag, attributionLabel, - usagesWithLabels.valueAt(usageNum), - VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT)); + usagesWithLabels.valueAt(usageNum), deviceId)); } } diff --git a/core/java/android/provider/ContactKeysManager.java b/core/java/android/provider/E2eeContactKeysManager.java index 01aaa3d9647e..b69441700b0a 100644 --- a/core/java/android/provider/ContactKeysManager.java +++ b/core/java/android/provider/E2eeContactKeysManager.java @@ -39,18 +39,18 @@ import java.util.List; import java.util.Objects; /** - * ContactKeysManager provides access to the provider of end-to-end encryption contact keys. - * It manages two types of keys - {@link ContactKey} and {@link SelfKey}. + * E2eeContactKeysManager provides access to the provider of end-to-end encryption contact keys. + * It manages two types of keys - {@link E2eeContactKey} and {@link E2eeSelfKey}. * <ul> * <li> - * A {@link ContactKey} is a public key associated with a contact. It's used to end-to-end + * A {@link E2eeContactKey} is a public key associated with a contact. It's used to end-to-end * encrypt the communications between a user and the contact. This API allows operations on - * {@link ContactKey}s to insert/update, remove, change the verification state, and retrieving + * {@link E2eeContactKey}s to insert/update, remove, change the verification state, and retrieving * keys (either created by or visible to the caller app). * </li> * <li> - * A {@link SelfKey} is a key for this device, so the key represents the owner of the device. - * This API allows operations on {@link SelfKey}s to insert/update, remove, and retrieving + * A {@link E2eeSelfKey} is a key for this device, so the key represents the owner of the device. + * This API allows operations on {@link E2eeSelfKey}s to insert/update, remove, and retrieving * self keys (either created by or visible to the caller app). * </li> * </ul> @@ -65,29 +65,30 @@ import java.util.Objects; * </li> * <li> * accountId - the app-specified identifier for the account for which the contact key can be used. - * Usually a phone number. + * Using different account IDs allows for multiple key entries representing the same user. + * For most apps this would be a phone number. * </li> * </ul> * Contact keys also use lookupKey which is an opaque value used to identify a contact in * ContactsProvider. */ @FlaggedApi(Flags.FLAG_USER_KEYS) -public final class ContactKeysManager { +public final class E2eeContactKeysManager { /** - * The authority for the contact keys provider. + * The authority for the end-to-end encryption contact keys provider. * @hide */ public static final String AUTHORITY = "com.android.contactkeys.contactkeysprovider"; /** - * A content:// style uri to the authority for the contact keys provider. + * A content:// style uri to the authority for the end-to-end encryption contact keys provider. * @hide */ @NonNull public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY); /** - * Maximum size of a contact key. + * Maximum size of an end-to-end encryption contact key. */ private static final int MAX_KEY_SIZE_BYTES = 5000; @@ -100,14 +101,15 @@ public final class ContactKeysManager { private final ContentResolver mContentResolver; /** @hide */ - public ContactKeysManager(@NonNull Context context) { + public E2eeContactKeysManager(@NonNull Context context) { Objects.requireNonNull(context); mContentResolver = context.getContentResolver(); } /** - * Inserts a new entry into the contact keys table or updates one if it already exists. - * The inserted/updated contact key is owned by the caller app. + * Inserts a new entry into the end-to-end encryption contact keys table or updates one if it + * already exists. + * The inserted/updated end-to-end encryption contact key is owned by the caller app. * * @param lookupKey value that references the contact * @param deviceId an app-specified identifier for the device @@ -115,76 +117,77 @@ public final class ContactKeysManager { * @param keyValue the raw bytes for the key (max size is {@link #getMaxKeySizeBytes} bytes) */ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) - public void updateOrInsertContactKey(@NonNull String lookupKey, + public void updateOrInsertE2eeContactKey(@NonNull String lookupKey, @NonNull String deviceId, @NonNull String accountId, @NonNull byte[] keyValue) { validateKeyLength(keyValue); Bundle extras = new Bundle(); - extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); - extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); - extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); - extras.putByteArray(ContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue)); + extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); + extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); + extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); + extras.putByteArray(E2eeContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue)); nullSafeCall(mContentResolver, - ContactKeys.UPDATE_OR_INSERT_CONTACT_KEY_METHOD, extras); + E2eeContactKeys.UPDATE_OR_INSERT_CONTACT_KEY_METHOD, extras); } /** - * Retrieves a contact key entry given the lookup key, device ID, accountId and inferred - * caller package name. + * Retrieves an end-to-end encryption contact key entry given the lookup key, device ID, + * accountId and inferred caller package name. * * @param lookupKey the value that references the contact * @param deviceId an app-specified identifier for the device * @param accountId an app-specified identifier for the account * - * @return a {@link ContactKey} object containing the contact key information, + * @return a {@link E2eeContactKey} object containing the contact key information, * or null if no contact key is found. */ @RequiresPermission(android.Manifest.permission.READ_CONTACTS) @Nullable - public ContactKey getContactKey( + public E2eeContactKey getE2eeContactKey( @NonNull String lookupKey, @NonNull String deviceId, @NonNull String accountId) { Bundle extras = new Bundle(); - extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); - extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); - extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); + extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); + extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); + extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); Bundle response = nullSafeCall(mContentResolver, - ContactKeys.GET_CONTACT_KEY_METHOD, extras); + E2eeContactKeys.GET_CONTACT_KEY_METHOD, extras); if (response == null) { return null; } - return response.getParcelable(ContactKeys.KEY_CONTACT_KEY, ContactKey.class); + return response.getParcelable(E2eeContactKeys.KEY_CONTACT_KEY, E2eeContactKey.class); } /** - * Retrieves all contact key entries that belong to apps visible to the caller. + * Retrieves all end-to-end encryption contact key entries that belong to apps visible to + * the caller. * The keys will be stripped of deviceId, timeUpdated and keyValue data. * * @param lookupKey the value that references the contact * - * @return a list of {@link ContactKey} objects containing the contact key + * @return a list of {@link E2eeContactKey} objects containing the contact key * information, or an empty list if no keys are found. */ @RequiresPermission(android.Manifest.permission.READ_CONTACTS) @NonNull - public List<ContactKey> getAllContactKeys(@NonNull String lookupKey) { + public List<E2eeContactKey> getAllE2eeContactKeys(@NonNull String lookupKey) { Bundle extras = new Bundle(); - extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); + extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); Bundle response = nullSafeCall(mContentResolver, - ContactKeys.GET_ALL_CONTACT_KEYS_METHOD, extras); + E2eeContactKeys.GET_ALL_CONTACT_KEYS_METHOD, extras); if (response == null) { return new ArrayList<>(); } - List<ContactKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS, - ContactKey.class); + List<E2eeContactKey> value = response.getParcelableArrayList( + E2eeContactKeys.KEY_CONTACT_KEYS, E2eeContactKey.class); if (value == null) { return new ArrayList<>(); } @@ -192,27 +195,28 @@ public final class ContactKeysManager { } /** - * Retrieves all contact key entries for a given lookupKey that belong to the caller app. + * Retrieves all end-to-end encryption contact key entries for a given lookupKey that belong to + * the caller app. * * @param lookupKey the value that references the contact * - * @return a list of {@link ContactKey} objects containing the contact key - * information, or an empty list if no keys are found. + * @return a list of {@link E2eeContactKey} objects containing the end-to-end encryption + * contact key information, or an empty list if no keys are found. */ @RequiresPermission(android.Manifest.permission.READ_CONTACTS) @NonNull - public List<ContactKey> getOwnerContactKeys(@NonNull String lookupKey) { + public List<E2eeContactKey> getOwnerE2eeContactKeys(@NonNull String lookupKey) { Bundle extras = new Bundle(); - extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); + extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); Bundle response = nullSafeCall(mContentResolver, - ContactKeys.GET_OWNER_CONTACT_KEYS_METHOD, extras); + E2eeContactKeys.GET_OWNER_CONTACT_KEYS_METHOD, extras); if (response == null) { return new ArrayList<>(); } - List<ContactKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS, - ContactKey.class); + List<E2eeContactKey> value = response.getParcelableArrayList( + E2eeContactKeys.KEY_CONTACT_KEYS, E2eeContactKey.class); if (value == null) { return new ArrayList<>(); } @@ -220,7 +224,8 @@ public final class ContactKeysManager { } /** - * Updates a contact key entry's local verification state that belongs to the caller app. + * Updates an end-to-end encryption contact key entry's local verification state that belongs + * to the caller app. * * @param lookupKey the value that references the contact * @param deviceId an app-specified identifier for the device @@ -230,27 +235,27 @@ public final class ContactKeysManager { * @return true if the entry was updated, false otherwise. */ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) - public boolean updateContactKeyLocalVerificationState(@NonNull String lookupKey, + public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String lookupKey, @NonNull String deviceId, @NonNull String accountId, @VerificationState int localVerificationState) { validateVerificationState(localVerificationState); Bundle extras = new Bundle(); - extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); - extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); - extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); - extras.putInt(ContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState); + extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); + extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); + extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); + extras.putInt(E2eeContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState); Bundle response = nullSafeCall(mContentResolver, - ContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras); + E2eeContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras); - return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS); + return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS); } /** - * Updates a contact key entry's local verification state that belongs to the app identified - * by ownerPackageName. + * Updates an end-to-end encryption contact key entry's local verification state that belongs + * to the app identified by ownerPackageName. * * @param lookupKey the value that references the contact * @param deviceId an app-specified identifier for the device @@ -266,7 +271,7 @@ public final class ContactKeysManager { @RequiresPermission(allOf = { android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) - public boolean updateContactKeyLocalVerificationState(@NonNull String lookupKey, + public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String lookupKey, @NonNull String deviceId, @NonNull String accountId, @NonNull String ownerPackageName, @@ -274,20 +279,22 @@ public final class ContactKeysManager { validateVerificationState(localVerificationState); final Bundle extras = new Bundle(); - extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); - extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); - extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); - extras.putString(ContactKeys.OWNER_PACKAGE_NAME, Objects.requireNonNull(ownerPackageName)); - extras.putInt(ContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState); + extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); + extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); + extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); + extras.putString(E2eeContactKeys.OWNER_PACKAGE_NAME, + Objects.requireNonNull(ownerPackageName)); + extras.putInt(E2eeContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState); final Bundle response = nullSafeCall(mContentResolver, - ContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras); + E2eeContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras); - return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS); + return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS); } /** - * Updates a contact key entry's remote verification state that belongs to the caller app. + * Updates an end-to-end encryption contact key entry's remote verification state that belongs + * to the caller app. * * @param lookupKey the value that references the contact * @param deviceId an app-specified identifier for the device @@ -297,27 +304,27 @@ public final class ContactKeysManager { * @return true if the entry was updated, false otherwise. */ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) - public boolean updateContactKeyRemoteVerificationState(@NonNull String lookupKey, + public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String lookupKey, @NonNull String deviceId, @NonNull String accountId, @VerificationState int remoteVerificationState) { validateVerificationState(remoteVerificationState); Bundle extras = new Bundle(); - extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); - extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); - extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); - extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState); + extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); + extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); + extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); + extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState); Bundle response = nullSafeCall(mContentResolver, - ContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras); + E2eeContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras); - return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS); + return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS); } /** - * Updates a contact key entry's remote verification state that belongs to the app identified - * by ownerPackageName. + * Updates an end-to-end encryption contact key entry's remote verification state that belongs + * to the app identified by ownerPackageName. * * @param lookupKey the value that references the contact * @param deviceId an app-specified identifier for the device @@ -333,7 +340,7 @@ public final class ContactKeysManager { @RequiresPermission(allOf = { android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) - public boolean updateContactKeyRemoteVerificationState(@NonNull String lookupKey, + public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String lookupKey, @NonNull String deviceId, @NonNull String accountId, @NonNull String ownerPackageName, @@ -341,19 +348,19 @@ public final class ContactKeysManager { validateVerificationState(remoteVerificationState); final Bundle extras = new Bundle(); - extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); - extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); - extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); - extras.putString(ContactKeys.OWNER_PACKAGE_NAME, Objects.requireNonNull(ownerPackageName)); - extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState); + extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); + extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); + extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); + extras.putString(E2eeContactKeys.OWNER_PACKAGE_NAME, + Objects.requireNonNull(ownerPackageName)); + extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState); final Bundle response = nullSafeCall(mContentResolver, - ContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras); + E2eeContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras); - return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS); + return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS); } - private static void validateVerificationState(int verificationState) { if (verificationState != VERIFICATION_STATE_UNVERIFIED && verificationState != VERIFICATION_STATE_VERIFICATION_FAILED @@ -364,7 +371,7 @@ public final class ContactKeysManager { } /** - * Removes a contact key entry that belongs to the caller app. + * Removes an end-to-end encryption contact key entry that belongs to the caller app. * * @param lookupKey the value that references the contact * @param deviceId an app-specified identifier for the device @@ -373,22 +380,23 @@ public final class ContactKeysManager { * @return true if the entry was removed, false otherwise. */ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) - public boolean removeContactKey(@NonNull String lookupKey, + public boolean removeE2eeContactKey(@NonNull String lookupKey, @NonNull String deviceId, @NonNull String accountId) { final Bundle extras = new Bundle(); - extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); - extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); - extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); + extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey)); + extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); + extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); final Bundle response = nullSafeCall(mContentResolver, - ContactKeys.REMOVE_CONTACT_KEY_METHOD, extras); + E2eeContactKeys.REMOVE_CONTACT_KEY_METHOD, extras); - return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS); + return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS); } /** - * Inserts a new entry into the self keys table or updates one if it already exists. + * Inserts a new entry into the end-to-end encryption self keys table or updates one if it + * already exists. * @param deviceId an app-specified identifier for the device * @param accountId an app-specified identifier for the account @@ -397,20 +405,20 @@ public final class ContactKeysManager { * @return true if the entry was added or updated, false otherwise. */ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) - public boolean updateOrInsertSelfKey(@NonNull String deviceId, + public boolean updateOrInsertE2eeSelfKey(@NonNull String deviceId, @NonNull String accountId, @NonNull byte[] keyValue) { validateKeyLength(keyValue); Bundle extras = new Bundle(); - extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); - extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); - extras.putByteArray(ContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue)); + extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); + extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); + extras.putByteArray(E2eeContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue)); Bundle response = nullSafeCall(mContentResolver, - ContactKeys.UPDATE_OR_INSERT_SELF_KEY_METHOD, extras); + E2eeContactKeys.UPDATE_OR_INSERT_SELF_KEY_METHOD, extras); - return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS); + return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS); } private static void validateKeyLength(byte[] keyValue) { @@ -422,7 +430,7 @@ public final class ContactKeysManager { } /** - * Updates a self key entry's remote verification state. + * Updates an end-to-end encryption self key entry's remote verification state. * * @param deviceId an app-specified identifier for the device * @param accountId an app-specified identifier for the account @@ -431,25 +439,25 @@ public final class ContactKeysManager { * @return true if the entry was updated, false otherwise. */ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) - public boolean updateSelfKeyRemoteVerificationState(@NonNull String deviceId, + public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String deviceId, @NonNull String accountId, @VerificationState int remoteVerificationState) { validateVerificationState(remoteVerificationState); Bundle extras = new Bundle(); - extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); - extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); - extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState); + extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); + extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); + extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState); Bundle response = nullSafeCall(mContentResolver, - ContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras); + E2eeContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras); - return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS); + return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS); } /** - * Updates a self key entry's remote verification state that belongs to the app identified - * by ownerPackageName. + * Updates an end-to-end encryption self key entry's remote verification state that belongs to + * the app identified by ownerPackageName. * * @param deviceId an app-specified identifier for the device * @param accountId an app-specified identifier for the account @@ -464,77 +472,79 @@ public final class ContactKeysManager { @RequiresPermission(allOf = { android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) - public boolean updateSelfKeyRemoteVerificationState(@NonNull String deviceId, + public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String deviceId, @NonNull String accountId, @NonNull String ownerPackageName, @VerificationState int remoteVerificationState) { validateVerificationState(remoteVerificationState); Bundle extras = new Bundle(); - extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); - extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); - extras.putString(ContactKeys.OWNER_PACKAGE_NAME, Objects.requireNonNull(ownerPackageName)); - extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState); + extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); + extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); + extras.putString(E2eeContactKeys.OWNER_PACKAGE_NAME, + Objects.requireNonNull(ownerPackageName)); + extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState); Bundle response = nullSafeCall(mContentResolver, - ContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras); + E2eeContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras); - return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS); + return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS); } /** - * Maximum size of a contact key. + * Maximum size of an end-to-end encryption contact key. */ public static int getMaxKeySizeBytes() { return MAX_KEY_SIZE_BYTES; } /** - * Returns a self key entry given the deviceId and the inferred package name of the caller. + * Returns an end-to-end encryption self key entry given the deviceId and the inferred package + * name of the caller. * * @param deviceId an app-specified identifier for the device * @param accountId an app-specified identifier for the account * - * @return a {@link SelfKey} object containing the self key information, or null if no self key - * is found. + * @return a {@link E2eeSelfKey} object containing the end-to-end encryption self key + * information, or null if no self key is found. */ @RequiresPermission(android.Manifest.permission.READ_CONTACTS) @Nullable - public SelfKey getSelfKey(@NonNull String deviceId, + public E2eeSelfKey getE2eeSelfKey(@NonNull String deviceId, @NonNull String accountId) { Bundle extras = new Bundle(); - extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); - extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); + extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); + extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); Bundle response = nullSafeCall(mContentResolver, - ContactKeys.GET_SELF_KEY_METHOD, extras); + E2eeContactKeys.GET_SELF_KEY_METHOD, extras); if (response == null) { return null; } - return response.getParcelable(ContactKeys.KEY_CONTACT_KEY, SelfKey.class); + return response.getParcelable(E2eeContactKeys.KEY_CONTACT_KEY, E2eeSelfKey.class); } /** - * Returns all self key entries that belong to apps visible to the caller. + * Returns all end-to-end encryption self key entries that belong to apps visible to the caller. * The keys will be stripped of deviceId, timeUpdated and keyValue data. * - * @return a list of {@link SelfKey} objects containing the self key information, or - * an empty list if no keys are found. + * @return a list of {@link E2eeSelfKey} objects containing the end-to-end encryption self key + * information, or an empty list if no self keys are found. */ @RequiresPermission(android.Manifest.permission.READ_CONTACTS) @NonNull - public List<SelfKey> getAllSelfKeys() { + public List<E2eeSelfKey> getAllE2eeSelfKeys() { Bundle extras = new Bundle(); - Bundle response = nullSafeCall(mContentResolver, ContactKeys.GET_ALL_SELF_KEYS_METHOD, + Bundle response = nullSafeCall(mContentResolver, E2eeContactKeys.GET_ALL_SELF_KEYS_METHOD, extras); if (response == null) { return new ArrayList<>(); } - List<SelfKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS, - SelfKey.class); + List<E2eeSelfKey> value = response.getParcelableArrayList(E2eeContactKeys.KEY_CONTACT_KEYS, + E2eeSelfKey.class); if (value == null) { return new ArrayList<>(); } @@ -542,24 +552,24 @@ public final class ContactKeysManager { } /** - * Returns all self key entries that are owned by the caller app. + * Returns all end-to-end encryption self key entries that are owned by the caller app. * - * @return a list of {@link SelfKey} objects containing the self key information, or - * an empty list if no keys are found. + * @return a list of {@link E2eeSelfKey} objects containing the end-to-end encryption self key + * information, or an empty list if no self keys are found. */ @RequiresPermission(android.Manifest.permission.READ_CONTACTS) @NonNull - public List<SelfKey> getOwnerSelfKeys() { + public List<E2eeSelfKey> getOwnerE2eeSelfKeys() { Bundle extras = new Bundle(); - Bundle response = nullSafeCall(mContentResolver, ContactKeys.GET_OWNER_SELF_KEYS_METHOD, + Bundle response = nullSafeCall(mContentResolver, E2eeContactKeys.GET_OWNER_SELF_KEYS_METHOD, extras); if (response == null) { return new ArrayList<>(); } - List<SelfKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS, - SelfKey.class); + List<E2eeSelfKey> value = response.getParcelableArrayList(E2eeContactKeys.KEY_CONTACT_KEYS, + E2eeSelfKey.class); if (value == null) { return new ArrayList<>(); } @@ -567,24 +577,24 @@ public final class ContactKeysManager { } /** - * Removes a self key entry given the deviceId and the inferred package name of the caller. - + * Removes an end-to-end encryption self key entry given the deviceId and the inferred + * package name of the caller. * @param deviceId an app-specified identifier for the device * @param accountId an app-specified identifier for the account * * @return true if the entry was removed, false otherwise. */ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) - public boolean removeSelfKey(@NonNull String deviceId, + public boolean removeE2eeSelfKey(@NonNull String deviceId, @NonNull String accountId) { Bundle extras = new Bundle(); - extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); - extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); + extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId)); + extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId)); Bundle response = nullSafeCall(mContentResolver, - ContactKeys.REMOVE_SELF_KEY_METHOD, extras); + E2eeContactKeys.REMOVE_SELF_KEY_METHOD, extras); - return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS); + return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS); } private Bundle nullSafeCall(@NonNull ContentResolver resolver, @NonNull String method, @@ -622,9 +632,9 @@ public final class ContactKeysManager { public static final int VERIFICATION_STATE_VERIFIED = 2; /** @hide */ - public static final class ContactKeys { + public static final class E2eeContactKeys { - private ContactKeys() {} + private E2eeContactKeys() {} /** * <p> @@ -636,14 +646,16 @@ public final class ContactKeysManager { /** * <p> - * An app-specified identifier for the device for which the contact key can be used. + * An app-specified identifier for the device for which the end-to-end encryption + * contact key can be used. * </p> */ public static final String DEVICE_ID = "device_id"; /** * <p> - * An app-specified identifier for the account for which the contact key can be used. + * An app-specified identifier for the account for which the end-to-end encryption + * contact key can be used. * Usually a phone number. * </p> */ @@ -718,29 +730,32 @@ public final class ContactKeysManager { public static final String GET_CONTACT_KEY_METHOD = "getContactKey"; /** - * The method to invoke in order to retrieve all contact keys. + * The method to invoke in order to retrieve all end-to-end encryption contact keys. */ public static final String GET_ALL_CONTACT_KEYS_METHOD = "getAllContactKeys"; /** - * The method to invoke in order to retrieve contact keys that belong to the caller. + * The method to invoke in order to retrieve end-to-end encryption contact keys that belong + * to the caller. */ public static final String GET_OWNER_CONTACT_KEYS_METHOD = "getOwnerContactKeys"; /** - * The method to invoke in order to update a contact key local verification state. + * The method to invoke in order to update an end-to-end encryption contact key local + * verification state. */ public static final String UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD = "updateContactKeyLocalVerificationState"; /** - * The method to invoke in order to update a contact key remote verification state. + * The method to invoke in order to update an end-to-end encryption contact key remote + * verification state. */ public static final String UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD = "updateContactKeyRemoteVerificationState"; /** - * The method to invoke in order to remove a contact key. + * The method to invoke in order to remove a end-to-end encryption contact key. */ public static final String REMOVE_CONTACT_KEY_METHOD = "removeContactKey"; @@ -776,12 +791,12 @@ public final class ContactKeysManager { public static final String REMOVE_SELF_KEY_METHOD = "removeSelfKey"; /** - * Key in the incoming Bundle for all the contact keys. + * Key in the incoming Bundle for all the end-to-end encryption contact keys. */ public static final String KEY_CONTACT_KEYS = "key_contact_keys"; /** - * Key in the incoming Bundle for a single contact key. + * Key in the incoming Bundle for a single end-to-end encryption contact key. */ public static final String KEY_CONTACT_KEY = "key_contact_key"; @@ -790,18 +805,19 @@ public final class ContactKeysManager { */ public static final String KEY_UPDATED_ROWS = "key_updated_rows"; } - /** * A parcelable class encapsulating other users' end to end encrypted contact key. */ - public static final class ContactKey implements Parcelable { + public static final class E2eeContactKey implements Parcelable { /** - * An app-specified identifier for the device for which the contact key can be used. + * An app-specified identifier for the device for which the end-to-end encryption + * contact key can be used. */ private final String mDeviceId; /** - * An app-specified identifier for the account for which the contact key can be used. + * An app-specified identifier for the account for which the end-to-end encryption + * contact key can be used. * Usually a phone number. */ private final String mAccountId; @@ -851,7 +867,7 @@ public final class ContactKeysManager { /** * @hide */ - public ContactKey(@Nullable String deviceId, @NonNull String accountId, + public E2eeContactKey(@Nullable String deviceId, @NonNull String accountId, @NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue, @VerificationState int localVerificationState, @VerificationState int remoteVerificationState, @@ -870,8 +886,10 @@ public final class ContactKeysManager { } /** - * Gets the app-specified identifier for the device for which the contact key can be used. - * Returns null if the app doesn't have the required visibility into the contact key. + * Gets the app-specified identifier for the device for which the end-to-end encryption + * contact key can be used. + * Returns null if the app doesn't have the required visibility into + * the end-to-end encryption contact key. * * @return An app-specified identifier for the device. */ @@ -881,7 +899,8 @@ public final class ContactKeysManager { } /** - * Gets the app-specified identifier for the account for which the contact key can be used. + * Gets the app-specified identifier for the account for which the end-to-end encryption + * contact key can be used. * Usually a phone number. * * @return An app-specified identifier for the account. @@ -903,7 +922,7 @@ public final class ContactKeysManager { /** * Gets the timestamp at which the key was updated. Returns -1 if the app doesn't have the - * required visibility into the contact key. + * required visibility into the end-to-end encryption contact key. * * @return The timestamp at which the key was updated in the System.currentTimeMillis() * base. @@ -914,7 +933,8 @@ public final class ContactKeysManager { /** * Gets the raw bytes for the key. - * Returns null if the app doesn't have the required visibility into the contact key. + * Returns null if the app doesn't have the required visibility into + * the end-to-end encryption contact key. * * @return A copy of the raw bytes for the key. */ @@ -984,7 +1004,7 @@ public final class ContactKeysManager { if (obj == null) return false; if (obj == this) return true; - if (!(obj instanceof ContactKey toCompare)) { + if (!(obj instanceof E2eeContactKey toCompare)) { return false; } @@ -1023,10 +1043,10 @@ public final class ContactKeysManager { } @NonNull - public static final Creator<ContactKey> CREATOR = + public static final Creator<E2eeContactKey> CREATOR = new Creator<>() { @Override - public ContactKey createFromParcel(Parcel source) { + public E2eeContactKey createFromParcel(Parcel source) { String deviceId = source.readString8(); String accountId = source.readString8(); String ownerPackageName = source.readString8(); @@ -1044,14 +1064,14 @@ public final class ContactKeysManager { String displayName = source.readString8(); String number = source.readString8(); String address = source.readString8(); - return new ContactKey(deviceId, accountId, ownerPackageName, + return new E2eeContactKey(deviceId, accountId, ownerPackageName, timeUpdated, keyValue, localVerificationState, remoteVerificationState, displayName, number, address); } @Override - public ContactKey[] newArray(int size) { - return new ContactKey[size]; + public E2eeContactKey[] newArray(int size) { + return new E2eeContactKey[size]; } }; } @@ -1059,14 +1079,16 @@ public final class ContactKeysManager { /** * A parcelable class encapsulating self end to end encrypted contact key. */ - public static final class SelfKey implements Parcelable { + public static final class E2eeSelfKey implements Parcelable { /** - * An app-specified identifier for the device for which the contact key can be used. + * An app-specified identifier for the device for which the end-to-end encryption + * contact key can be used. */ private final String mDeviceId; /** - * An app-specified identifier for the account for which the contact key can be used. + * An app-specified identifier for the account for which the end-to-end encryption + * contact key can be used. * Usually a phone number. */ private final String mAccountId; @@ -1096,7 +1118,7 @@ public final class ContactKeysManager { /** * @hide */ - public SelfKey(@Nullable String deviceId, @NonNull String accountId, + public E2eeSelfKey(@Nullable String deviceId, @NonNull String accountId, @NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue, @VerificationState int remoteVerificationState) { this.mDeviceId = deviceId; @@ -1108,8 +1130,10 @@ public final class ContactKeysManager { } /** - * Gets the app-specified identifier for the device for which the contact key can be used. - * Returns null if the app doesn't have the required visibility into the contact key. + * Gets the app-specified identifier for the device for which the end-to-end encryption + * contact key can be used. + * Returns null if the app doesn't have the required visibility into + * the end-to-end encryption contact key. * * @return An app-specified identifier for the device. */ @@ -1119,7 +1143,8 @@ public final class ContactKeysManager { } /** - * Gets the app-specified identifier for the account for which the contact key can be used. + * Gets the app-specified identifier for the account for which the end-to-end encryption + * contact key can be used. * Usually a phone number. * * @return An app-specified identifier for the device. @@ -1141,7 +1166,7 @@ public final class ContactKeysManager { /** * Gets the timestamp at which the key was updated. Returns -1 if the app doesn't have the - * required visibility into the contact key. + * required visibility into the end-to-end encryption contact key. * * @return The timestamp at which the key was updated in the System.currentTimeMillis() * base. @@ -1152,7 +1177,8 @@ public final class ContactKeysManager { /** * Gets the raw bytes for the key. - * Returns null if the app doesn't have the required visibility into the contact key. + * Returns null if the app doesn't have the required visibility into + * the end-to-end encryption contact key. * * @return A copy of the raw bytes for the key. */ @@ -1182,7 +1208,7 @@ public final class ContactKeysManager { if (obj == null) return false; if (obj == this) return true; - if (!(obj instanceof SelfKey toCompare)) { + if (!(obj instanceof E2eeSelfKey toCompare)) { return false; } @@ -1213,10 +1239,10 @@ public final class ContactKeysManager { } @NonNull - public static final Creator<SelfKey> CREATOR = + public static final Creator<E2eeSelfKey> CREATOR = new Creator<>() { @Override - public SelfKey createFromParcel(Parcel source) { + public E2eeSelfKey createFromParcel(Parcel source) { String deviceId = source.readString8(); String accountId = source.readString8(); String ownerPackageName = source.readString8(); @@ -1230,13 +1256,13 @@ public final class ContactKeysManager { keyValue = null; } int remoteVerificationState = source.readInt(); - return new SelfKey(deviceId, accountId, ownerPackageName, + return new E2eeSelfKey(deviceId, accountId, ownerPackageName, timeUpdated, keyValue, remoteVerificationState); } @Override - public SelfKey[] newArray(int size) { - return new SelfKey[size]; + public E2eeSelfKey[] newArray(int size) { + return new E2eeSelfKey[size]; } }; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 50adc40e719d..20b4857bdd4d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -11969,6 +11969,16 @@ public final class Settings { "accessibility_pinch_to_zoom_anywhere_enabled"; /** + * For magnification feature where panning can be controlled with a single finger. + * + * If true, you can pan using a single finger gesture. + * + * @hide + */ + public static final String ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED = + "accessibility_single_finger_panning_enabled"; + + /** * Controls magnification capability. Accessibility magnification is capable of at least one * of the magnification modes. * diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig index 76314546b4f0..5e7edda31c19 100644 --- a/core/java/android/security/flags.aconfig +++ b/core/java/android/security/flags.aconfig @@ -31,6 +31,13 @@ flag { } flag { + name: "keyinfo_unlocked_device_required" + namespace: "hardware_backed_security" + description: "Add the API android.security.keystore.KeyInfo#isUnlockedDeviceRequired()" + bug: "296475382" +} + +flag { name: "deprecate_fsv_sig" namespace: "hardware_backed_security" description: "Feature flag for deprecating .fsv_sig" diff --git a/core/java/android/service/chooser/flags.aconfig b/core/java/android/service/chooser/flags.aconfig index 00236dfa7876..d72441f1e4b7 100644 --- a/core/java/android/service/chooser/flags.aconfig +++ b/core/java/android/service/chooser/flags.aconfig @@ -27,3 +27,14 @@ flag { description: "Provides additional callbacks with information about user actions in ChooserResult" bug: "263474465" } + +flag { + name: "legacy_chooser_pinning_removal" + namespace: "intentresolver" + description: "Removing pinning functionality from the legacy chooser (used by partial screenshare)" + bug: "301068735" + metadata { + purpose: PURPOSE_BUGFIX + } +} + diff --git a/core/java/android/tracing/perfetto/DataSource.java b/core/java/android/tracing/perfetto/DataSource.java index 4e08aeef88e6..d0c719b86ac9 100644 --- a/core/java/android/tracing/perfetto/DataSource.java +++ b/core/java/android/tracing/perfetto/DataSource.java @@ -18,6 +18,8 @@ package android.tracing.perfetto; import android.util.proto.ProtoInputStream; +import com.android.internal.annotations.VisibleForTesting; + /** * Templated base class meant to be derived by embedders to create a custom data * source. @@ -87,7 +89,8 @@ public abstract class DataSource<DataSourceInstanceType extends DataSourceInstan * * NOTE: Should only be called from native side. */ - protected TlsStateType createTlsState(CreateTlsStateArgs<DataSourceInstanceType> args) { + @VisibleForTesting + public TlsStateType createTlsState(CreateTlsStateArgs<DataSourceInstanceType> args) { return null; } diff --git a/core/java/android/tracing/perfetto/DataSourceInstance.java b/core/java/android/tracing/perfetto/DataSourceInstance.java index 3710b4df33e8..904cf55e014a 100644 --- a/core/java/android/tracing/perfetto/DataSourceInstance.java +++ b/core/java/android/tracing/perfetto/DataSourceInstance.java @@ -16,6 +16,8 @@ package android.tracing.perfetto; +import com.android.internal.annotations.VisibleForTesting; + /** * @hide */ @@ -66,7 +68,8 @@ public abstract class DataSourceInstance implements AutoCloseable { * Only required to be called when instance was retrieved with * `DataSource#getDataSourceInstanceLocked`. */ - public final void release() { + @VisibleForTesting + public void release() { mDataSource.releaseDataSourceInstance(mInstanceIndex); } diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java index b33214dffb7e..8358b9a51adb 100644 --- a/core/java/android/util/Log.java +++ b/core/java/android/util/Log.java @@ -72,8 +72,11 @@ import java.net.UnknownHostException; * a positive value may be considered as a successful invocation. */ @android.ravenwood.annotation.RavenwoodKeepWholeClass -@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass( - "com.android.platform.test.ravenwood.nativesubstitution.Log_host") +@android.ravenwood.annotation.RavenwoodClassLoadHook( + "com.android.platform.test.ravenwood.runtimehelper.ClassLoadHook.onClassLoaded") +// Uncomment the following annotation to switch to the Java substitution version. +//@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass( +// "com.android.platform.test.ravenwood.nativesubstitution.Log_host") public final class Log { /** @hide */ @IntDef({ASSERT, ERROR, WARN, INFO, DEBUG, VERBOSE}) diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS index ad326e41a146..a2f767d002f4 100644 --- a/core/java/android/view/OWNERS +++ b/core/java/android/view/OWNERS @@ -102,6 +102,7 @@ per-file ISurfaceControlViewHost*.aidl = file:/services/core/java/com/android/se per-file IWindow*.aidl = file:/services/core/java/com/android/server/wm/OWNERS per-file RemoteAnimation*.java = file:/services/core/java/com/android/server/wm/OWNERS per-file RemoteAnimation*.aidl = file:/services/core/java/com/android/server/wm/OWNERS +per-file ScreenRecordingCallbacks.java = file:/services/core/java/com/android/server/wm/OWNERS per-file *SurfaceControl*.java = file:/services/core/java/com/android/server/wm/OWNERS per-file SurfaceControl*.aidl = file:/services/core/java/com/android/server/wm/OWNERS per-file SurfaceSession.java = file:/services/core/java/com/android/server/wm/OWNERS diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index 13b9c4518711..f5f4fd9f7042 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -480,11 +480,19 @@ public final class PointerIcon implements Parcelable { mBitmapFrames = new Bitmap[frames - 1]; final int width = drawable.getIntrinsicWidth(); final int height = drawable.getIntrinsicHeight(); + final boolean isVectorAnimation = drawable instanceof VectorDrawable; + mDrawNativeDropShadow = isVectorAnimation; for (int i = 1; i < frames; ++i) { Drawable drawableFrame = animationDrawable.getFrame(i); - if (!(drawableFrame instanceof BitmapDrawable)) { + if (!(drawableFrame instanceof BitmapDrawable) + && !(drawableFrame instanceof VectorDrawable)) { throw new IllegalArgumentException("Frame of an animated pointer icon " - + "must refer to a bitmap drawable."); + + "must refer to a bitmap drawable or vector drawable."); + } + if (isVectorAnimation != (drawableFrame instanceof VectorDrawable)) { + throw new IllegalArgumentException("The drawable of the " + i + "-th frame " + + "is a different type from the others. All frames should be the " + + "same type."); } if (drawableFrame.getIntrinsicWidth() != width || drawableFrame.getIntrinsicHeight() != height) { @@ -492,8 +500,11 @@ public final class PointerIcon implements Parcelable { + "is different. All frames should have the exact same size and " + "share the same hotspot."); } - BitmapDrawable bitmapDrawableFrame = (BitmapDrawable) drawableFrame; - mBitmapFrames[i - 1] = getBitmapFromDrawable(bitmapDrawableFrame); + if (isVectorAnimation) { + drawableFrame = getBitmapDrawableFromVectorDrawable(resources, + (VectorDrawable) drawableFrame); + } + mBitmapFrames[i - 1] = getBitmapFromDrawable((BitmapDrawable) drawableFrame); } } } diff --git a/core/java/android/view/RoundedCorners.java b/core/java/android/view/RoundedCorners.java index f68cc691abeb..1f841bf53364 100644 --- a/core/java/android/view/RoundedCorners.java +++ b/core/java/android/view/RoundedCorners.java @@ -198,6 +198,12 @@ public class RoundedCorners implements Parcelable { radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius); } array.recycle(); + // For devices with round displays (e.g. watches) that don't otherwise provide the rounded + // corner radius via resource overlays, we can infer the corner radius directly from the + // display size. + if (radius == 0 && res.getConfiguration().isScreenRound()) { + radius = res.getDisplayMetrics().widthPixels / 2; + } return radius; } diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 896b3f4bd5c3..124aecef1d5a 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -16,6 +16,8 @@ package android.view; +import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL; + import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; @@ -883,6 +885,17 @@ public class TextureView extends View { mListener = listener; } + /** + * @hide + */ + @Override + protected int calculateFrameRateCategory(float sizePercentage) { + if (mMinusTwoFrameIntervalMillis > 15 && mMinusOneFrameIntervalMillis > 15) { + return FRAME_RATE_CATEGORY_NORMAL; + } + return super.calculateFrameRateCategory(sizePercentage); + } + @UnsupportedAppUsage private final SurfaceTexture.OnFrameAvailableListener mUpdateListener = surfaceTexture -> { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 4df95bf31c3f..042af1f0fb15 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5649,9 +5649,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private int mInfrequentUpdateCount = 0; private long mLastUpdateTimeMillis = 0; - private long mMinusOneFrameIntervalMillis = 0; - private long mMinusTwoFrameIntervalMillis = 0; - private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_HIGH; + /** + * @hide + */ + protected long mMinusOneFrameIntervalMillis = 0; + /** + * @hide + */ + protected long mMinusTwoFrameIntervalMillis = 0; + private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE; @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = Float.NaN; @@ -9952,6 +9958,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * @hide + */ + public void onGetCredentialException(String errorType, String errorMsg) { + if (getCredentialManagerCallback() == null) { + Log.w(AUTOFILL_LOG_TAG, "onGetCredentialException called but no callback found"); + return; + } + getCredentialManagerCallback().onError(new GetCredentialException(errorType, errorMsg)); + } + + /** * Gets the unique, logical identifier of this view in the activity, for autofill purposes. * * <p>The autofill id is created on demand, unless it is explicitly set by @@ -15297,6 +15314,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * {@link #isLongClickable()}, {@link #isContextClickable()}, * {@link #isScreenReaderFocusable()}, or {@link #isFocusable()} * <li>Has an {@link AccessibilityDelegate} + * <li>Has an {@link AccessibilityNodeProvider} * <li>Has an interaction listener, e.g. {@link OnTouchListener}, * {@link OnKeyListener}, etc. * <li>Is an accessibility live region, e.g. @@ -15329,7 +15347,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() - || hasListenersForAccessibility() || mAccessibilityDelegate != null + || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null + || getAccessibilityDelegate() != null || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE || isAccessibilityPane() || isAccessibilityHeading(); } @@ -33612,7 +33631,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return (float) viewSize / screenSize; } - private int calculateFrameRateCategory(float sizePercentage) { + /** + * Used to calculate the frame rate category of a View. + * + * @hide + */ + protected int calculateFrameRateCategory(float sizePercentage) { if (mMinusTwoFrameIntervalMillis + mMinusOneFrameIntervalMillis < INFREQUENT_UPDATE_INTERVAL_MILLIS) { if (sizePercentage <= FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD) { @@ -33746,7 +33770,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mMinusTwoFrameIntervalMillis = mMinusOneFrameIntervalMillis; mMinusOneFrameIntervalMillis = timeIntervalMillis; - mLastUpdateTimeMillis = currentTimeMillis; + if (mMinusOneFrameIntervalMillis - mMinusTwoFrameIntervalMillis >= 30 + && timeIntervalMillis < 2) { + return; + } if (timeIntervalMillis >= INFREQUENT_UPDATE_INTERVAL_MILLIS) { mInfrequentUpdateCount = mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS ? mInfrequentUpdateCount : mInfrequentUpdateCount + 1; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 23a7017b6125..333cbb39d9c7 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -95,12 +95,14 @@ import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED; import static android.view.accessibility.Flags.fixMergedContentChangeEvent; import static android.view.accessibility.Flags.forceInvertColor; import static android.view.accessibility.Flags.reduceWindowContentChangedEventThrottle; +import static android.view.flags.Flags.toolkitFrameRateTypingReadOnly; import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision; import static android.view.flags.Flags.toolkitSetFrameRateReadOnly; import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER; import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER; import static com.android.input.flags.Flags.enablePointerChoreographer; +import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay; import android.Manifest; import android.accessibilityservice.AccessibilityService; @@ -997,8 +999,6 @@ public final class ViewRootImpl implements ViewParent, */ private final boolean mViewBoundsSandboxingEnabled; - private int mLastTransformHint = Integer.MIN_VALUE; - private AccessibilityWindowAttributes mAccessibilityWindowAttributes; /* @@ -1044,7 +1044,7 @@ public final class ViewRootImpl implements ViewParent, // time for checking idle status periodically. private static final int FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS = 500; // time for revaluating the idle status before lowering the frame rate. - private static final int FRAME_RATE_IDLENESS_REEVALUATE_TIME = 500; + private static final int FRAME_RATE_IDLENESS_REEVALUATE_TIME = 1000; // time for evaluating the interval between current time and // the time when frame rate was set previously. private static final int FRAME_RATE_SETTING_REEVALUATE_TIME = 100; @@ -1062,9 +1062,6 @@ public final class ViewRootImpl implements ViewParent, * the variables below are used to determine whther a dVRR feature should be enabled */ - // Used to determine whether to suppress boost on typing - private boolean mShouldSuppressBoostOnTyping = false; - /** * A temporary object used so relayoutWindow can return the latest SyncSeqId * system. The SyncSeqId system was designed to work without synchronous relayout @@ -1118,10 +1115,12 @@ public final class ViewRootImpl implements ViewParent, private static boolean sToolkitSetFrameRateReadOnlyFlagValue; private static boolean sToolkitMetricsForFrameRateDecisionFlagValue; + private static boolean sToolkitFrameRateTypingReadOnlyFlagValue; static { sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly(); sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision(); + sToolkitFrameRateTypingReadOnlyFlagValue = toolkitFrameRateTypingReadOnly(); } // The latest input event from the gesture that was used to resolve the pointer icon. @@ -6541,6 +6540,7 @@ public final class ViewRootImpl implements ViewParent, mHasInvalidation = false; mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, FRAME_RATE_IDLENESS_REEVALUATE_TIME); + mHasIdledMessage = true; } break; case MSG_REFRESH_POINTER_ICON: @@ -8918,11 +8918,13 @@ public final class ViewRootImpl implements ViewParent, final int transformHint = SurfaceControl.rotationToBufferTransform( (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4); + final boolean transformHintChanged = transformHint != mPreviousTransformHint; + mPreviousTransformHint = transformHint; + mSurfaceControl.setTransformHint(transformHint); WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth, requestedHeight, mWinFrameInScreen, mPendingDragResizing, mSurfaceSize); - final boolean transformHintChanged = transformHint != mLastTransformHint; final boolean sizeChanged = !mLastSurfaceSize.equals(mSurfaceSize); final boolean surfaceControlChanged = (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) == RELAYOUT_RES_SURFACE_CHANGED; @@ -8951,10 +8953,6 @@ public final class ViewRootImpl implements ViewParent, } } - mLastTransformHint = transformHint; - - mSurfaceControl.setTransformHint(transformHint); - if (mAttachInfo.mContentCaptureManager != null) { ContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager .getMainContentCaptureSession(); @@ -8968,8 +8966,7 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue); } mHdrRenderState.forceUpdateHdrSdrRatio(); - if (mPreviousTransformHint != transformHint) { - mPreviousTransformHint = transformHint; + if (transformHintChanged) { dispatchTransformHintChanged(transformHint); } } else { @@ -11933,6 +11930,14 @@ public final class ViewRootImpl implements ViewParent, @Override public @SurfaceControl.BufferTransform int getBufferTransformHint() { + // TODO(b/326482114) We use mPreviousTransformHint (calculated using mDisplay's rotation) + // instead of mSurfaceControl#getTransformHint because there's a race where SurfaceFlinger + // can set an incorrect transform hint for a few frames before it is aware of the updated + // display rotation. + if (enableBufferTransformHintFromDisplay()) { + return mPreviousTransformHint; + } + if (mSurfaceControl.isValid()) { return mSurfaceControl.getTransformHint(); } else { @@ -12364,14 +12369,6 @@ public final class ViewRootImpl implements ViewParent, } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } - - if (mPreferredFrameRateCategory != FRAME_RATE_CATEGORY_NO_PREFERENCE && !mHasIdledMessage) { - // Check where the display is idled periodically. - // If so, set the frame rate category to NO_PREFERENCE - mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, - FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS); - mHasIdledMessage = true; - } } private void setPreferredFrameRate(float preferredFrameRate) { @@ -12385,7 +12382,8 @@ public final class ViewRootImpl implements ViewParent, if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { Trace.traceBegin( Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate " - + preferredFrameRate); + + preferredFrameRate + " compatibility " + + mFrameRateCompatibility); } mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate, mFrameRateCompatibility).applyAsyncUnsafe(); @@ -12411,7 +12409,7 @@ public final class ViewRootImpl implements ViewParent, private boolean shouldSetFrameRate() { // use toolkitSetFrameRate flag to gate the change - return mSurface.isValid() && mPreferredFrameRate > 0 + return mSurface.isValid() && mPreferredFrameRate >= 0 && shouldEnableDvrr() && !mIsFrameRateConflicted; } @@ -12419,7 +12417,8 @@ public final class ViewRootImpl implements ViewParent, boolean desiredAction = motionEventAction == MotionEvent.ACTION_DOWN || motionEventAction == MotionEvent.ACTION_MOVE || motionEventAction == MotionEvent.ACTION_UP; - boolean undesiredType = windowType == TYPE_INPUT_METHOD && mShouldSuppressBoostOnTyping; + boolean undesiredType = windowType == TYPE_INPUT_METHOD + && sToolkitFrameRateTypingReadOnlyFlagValue; // use toolkitSetFrameRate flag to gate the change return desiredAction && !undesiredType && shouldEnableDvrr() && getFrameRateBoostOnTouchEnabled(); @@ -12452,6 +12451,7 @@ public final class ViewRootImpl implements ViewParent, mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW; } mHasInvalidation = true; + checkIdleness(); } /** @@ -12494,6 +12494,7 @@ public final class ViewRootImpl implements ViewParent, mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING, FRAME_RATE_SETTING_REEVALUATE_TIME); } + checkIdleness(); } /** @@ -12599,4 +12600,14 @@ public final class ViewRootImpl implements ViewParent, private boolean shouldEnableDvrr() { return sToolkitSetFrameRateReadOnlyFlagValue && mIsFrameRatePowerSavingsBalanced; } + + private void checkIdleness() { + if (!mHasIdledMessage) { + // Check where the display is idled periodically. + // If so, set the frame rate category to NO_PREFERENCE + mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE, + FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS); + mHasIdledMessage = true; + } + } } diff --git a/core/java/android/view/accessibility/IMagnificationConnection.aidl b/core/java/android/view/accessibility/IMagnificationConnection.aidl index aae51abd3c78..450cf7558c6f 100644 --- a/core/java/android/view/accessibility/IMagnificationConnection.aidl +++ b/core/java/android/view/accessibility/IMagnificationConnection.aidl @@ -124,4 +124,9 @@ oneway interface IMagnificationConnection { * @param scale magnification scale. */ void onUserMagnificationScaleChanged(int userId, int displayId, float scale); + + /** + * Notify the changes of fullscreen magnification activation on the specified display + */ + void onFullscreenMagnificationActivationChanged(int displayId, boolean activated); } diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 364c94f7f92f..64e5a5bb87a2 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -50,6 +50,7 @@ import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.credentials.GetCredentialException; import android.credentials.GetCredentialResponse; import android.graphics.Rect; import android.metrics.LogMaker; @@ -105,6 +106,7 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.PrintWriter; +import java.io.Serializable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; @@ -2400,6 +2402,13 @@ public final class AutofillManager { final Bundle responseData = new Bundle(); responseData.putParcelable(EXTRA_AUTHENTICATION_RESULT, result); + Serializable exception = data.getSerializableExtra( + CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION, + GetCredentialException.class); + if (exception != null && Flags.autofillCredmanIntegration()) { + responseData.putSerializable( + CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION, exception); + } final Bundle newClientState = data.getBundleExtra(EXTRA_CLIENT_STATE); if (newClientState != null) { responseData.putBundle(EXTRA_CLIENT_STATE, newClientState); @@ -2926,6 +2935,48 @@ public final class AutofillManager { } } + private void onGetCredentialException(int sessionId, AutofillId id, String errorType, + String errorMsg) { + synchronized (mLock) { + if (sessionId != mSessionId) { + Log.w(TAG, "onGetCredentialException afm sessionIds don't match"); + return; + } + + final AutofillClient client = getClient(); + if (client == null) { + Log.w(TAG, "onGetCredentialException afm client id null"); + return; + } + ArrayList<AutofillId> failedIds = new ArrayList<>(); + final View[] views = client.autofillClientFindViewsByAutofillIdTraversal( + Helper.toArray(new ArrayList<>(Collections.singleton(id)))); + if (views == null || views.length == 0) { + Log.w(TAG, "onGetCredentialException afm client view not found"); + return; + } + + final View view = views[0]; + if (view == null) { + Log.i(TAG, "onGetCredentialException View is null"); + + // Most likely view has been removed after the initial request was sent to the + // the service; this is fine, but we need to update the view status in the + // server side so it can be triggered again. + Log.d(TAG, "onGetCredentialException(): no View with id " + id); + failedIds.add(id); + } + if (id.isVirtualInt()) { + Log.i(TAG, "onGetCredentialException afm client id is virtual"); + // TODO(b/326314286): Handle virtual views + } else { + Log.i(TAG, "onGetCredentialException afm client id is NOT virtual"); + view.onGetCredentialException(errorType, errorMsg); + } + handleFailedIdsLocked(failedIds); + } + } + private void onGetCredentialResponse(int sessionId, AutofillId id, GetCredentialResponse response) { synchronized (mLock) { @@ -4382,6 +4433,15 @@ public final class AutofillManager { } @Override + public void onGetCredentialException(int sessionId, AutofillId id, + String errorType, String errorMsg) { + final AutofillManager afm = mAfm.get(); + if (afm != null) { + afm.post(() -> afm.onGetCredentialException(sessionId, id, errorType, errorMsg)); + } + } + + @Override public void autofillContent(int sessionId, AutofillId id, ClipData content) { final AutofillManager afm = mAfm.get(); if (afm != null) { diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl index e838027a9ae1..904a7e0d6173 100644 --- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl +++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl @@ -49,9 +49,12 @@ oneway interface IAutoFillManagerClient { void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values, boolean hideHighlight); - void onGetCredentialResponse(int sessionId, in AutofillId id, + void onGetCredentialResponse(int sessionId, in AutofillId id, in GetCredentialResponse response); + void onGetCredentialException(int sessionId, in AutofillId id, + in String errorType, in String errorMsg); + /** * Autofills the activity with rich content data (e.g. an image) from a dataset. */ diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig index 9d613bcae29a..05cabd56f532 100644 --- a/core/java/android/view/flags/refresh_rate_flags.aconfig +++ b/core/java/android/view/flags/refresh_rate_flags.aconfig @@ -74,4 +74,12 @@ flag { description: "Feature flag for setting frame rate based on velocity" bug: "239979904" is_fixed_read_only: true +} + +flag { + name: "toolkit_frame_rate_typing_read_only" + namespace: "toolkit" + description: "Feature flag for suppressing boost on typing" + bug: "239979904" + is_fixed_read_only: true }
\ No newline at end of file diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java index 74e1d10cdd44..b1fdaa97ffe0 100644 --- a/core/java/android/view/inputmethod/ImeTracker.java +++ b/core/java/android/view/inputmethod/ImeTracker.java @@ -340,15 +340,6 @@ public interface ImeTracker { @SoftInputShowHideReason int reason, boolean fromUser); /** - * Alias for {@link #onRequestShow(String, int, int, int, boolean)} with - * {@code fromUser} set to {@code false}. - */ - default Token onRequestShow(@Nullable String component, int uid, @Origin int origin, - @SoftInputShowHideReason int reason) { - return onRequestShow(component, uid, origin, reason, false /* fromUser */); - } - - /** * Creates an IME hide request tracking token. * * @param component the name of the component that created the IME request, or {@code null} @@ -365,15 +356,6 @@ public interface ImeTracker { @SoftInputShowHideReason int reason, boolean fromUser); /** - * Alias for {@link #onRequestHide(String, int, int, int, boolean)} with - * {@code fromUser} set to {@code false}. - */ - default Token onRequestHide(@Nullable String component, int uid, @Origin int origin, - @SoftInputShowHideReason int reason) { - return onRequestHide(component, uid, origin, reason, false /* fromUser */); - } - - /** * Called when an IME request progresses to a further phase. * * @param token the token tracking the current IME request or {@code null} otherwise. diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java index 7c9678f11e0e..16fecc17d426 100644 --- a/core/java/android/view/inputmethod/InputMethodInfo.java +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -497,6 +497,25 @@ public final class InputMethodInfo implements Parcelable { * @hide */ @TestApi + public InputMethodInfo(@NonNull String packageName, @NonNull String className, + @NonNull CharSequence label, @NonNull String settingsActivity, + @NonNull String languageSettingsActivity, boolean supportStylusHandwriting, + @NonNull String stylusHandwritingSettingsActivityAttr) { + this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */, + settingsActivity, languageSettingsActivity, null /* subtypes */, + 0 /* isDefaultResId */, false /* forceDefault */, + true /* supportsSwitchingToNextInputMethod */, + false /* inlineSuggestionsEnabled */, false /* isVrOnly */, + false /* isVirtualDeviceOnly */, 0 /* handledConfigChanges */, + supportStylusHandwriting, false /* supportConnectionlessStylusHandwriting */, + stylusHandwritingSettingsActivityAttr, false /* inlineSuggestionsEnabled */); + } + + /** + * Test API for creating a built-in input method to verify stylus handwriting. + * @hide + */ + @TestApi @FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING) public InputMethodInfo(@NonNull String packageName, @NonNull String className, @NonNull CharSequence label, @NonNull String settingsActivity, diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 3bce155049c8..fcc8344cbcd9 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -2328,7 +2328,7 @@ public final class InputMethodManager { synchronized (mH) { final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestShow( null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT, - SoftInputShowHideReason.SHOW_SOFT_INPUT); + SoftInputShowHideReason.SHOW_SOFT_INPUT, false /* fromUser */); Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be" + " removed soon. If you are using androidx.appcompat.widget.SearchView," @@ -3490,8 +3490,7 @@ public final class InputMethodManager { return false; } mServedView = mNextServedView; - if (initiationWithoutInputConnection() && mServedView.onCheckIsTextEditor() - && mServedView.isHandwritingDelegate()) { + if (initiationWithoutInputConnection() && mServedView.isHandwritingDelegate()) { mServedView.getViewRootImpl().getHandwritingInitiator().onDelegateViewFocused( mServedView); } @@ -3539,7 +3538,7 @@ public final class InputMethodManager { void closeCurrentInput() { final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide( null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, - SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION); + SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION, false /* fromUser */); ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION, ActivityThread::currentApplication); @@ -3639,7 +3638,7 @@ public final class InputMethodManager { if (statsToken == null) { statsToken = ImeTracker.forLogging().onRequestHide(null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, - SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API); + SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API, false /* fromUser */); } ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API, diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 13dc4efb374d..0e5747d0e445 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -3874,7 +3874,7 @@ public class RemoteViews implements Parcelable, Filter { } } - private static class SetDrawInstructionAction extends Action { + private class SetDrawInstructionAction extends Action { @Nullable private final DrawInstructions mInstructions; @@ -3909,6 +3909,15 @@ public class RemoteViews implements Parcelable, Filter { } try (ByteArrayInputStream is = new ByteArrayInputStream(bytes.get(0))) { player.setDocument(new RemoteComposeDocument(is)); + player.addClickListener((viewId, metadata) -> { + mActions.forEach(action -> { + if (viewId == action.mViewId + && action instanceof SetOnClickResponse setOnClickResponse) { + setOnClickResponse.mResponse.handleViewInteraction( + player, params.handler); + } + }); + }); } catch (IOException e) { Log.e(LOG_TAG, "Failed to render draw instructions", e); } @@ -6051,16 +6060,6 @@ public class RemoteViews implements Parcelable, Filter { RemoteViews rvToApply = getRemoteViewsToApply(context, size); View result = inflateView(context, rvToApply, directParent, params.applyThemeResId, params.colorResources); - if (result instanceof RemoteComposePlayer player) { - player.addClickListener((viewId, metadata) -> { - mActions.forEach(action -> { - if (viewId == action.mViewId - && action instanceof SetOnClickResponse setOnClickResponse) { - setOnClickResponse.mResponse.handleViewInteraction(player, params.handler); - } - }); - }); - } rvToApply.performApply(result, rootParent, params); return result; } diff --git a/core/java/android/widget/flags/notification_widget_flags.aconfig b/core/java/android/widget/flags/notification_widget_flags.aconfig index bfe3d052479b..e60fa157e8e4 100644 --- a/core/java/android/widget/flags/notification_widget_flags.aconfig +++ b/core/java/android/widget/flags/notification_widget_flags.aconfig @@ -15,4 +15,14 @@ flag { metadata { purpose: PURPOSE_BUGFIX } +} + +flag { + name: "conversation_style_set_avatar_async" + namespace: "systemui" + description: "Offloads conversation avatar drawable loading to the background thread" + bug: "305540309" + metadata { + purpose: PURPOSE_BUGFIX + } }
\ No newline at end of file diff --git a/core/java/android/window/flags/OWNERS b/core/java/android/window/flags/OWNERS index 3fa376003123..fd73d35e00d2 100644 --- a/core/java/android/window/flags/OWNERS +++ b/core/java/android/window/flags/OWNERS @@ -1,2 +1,3 @@ per-file responsible_apis.aconfig = file:/BAL_OWNERS per-file large_screen_experiences_app_compat.aconfig = file:/LSE_APP_COMPAT_OWNERS +per-file accessibility.aconfig = file:/core/java/android/view/accessibility/OWNERS diff --git a/core/java/android/window/flags/accessibility.aconfig b/core/java/android/window/flags/accessibility.aconfig index d467be6e5311..814c62017391 100644 --- a/core/java/android/window/flags/accessibility.aconfig +++ b/core/java/android/window/flags/accessibility.aconfig @@ -5,4 +5,11 @@ flag { namespace: "accessibility" description: "The flag controls whether the intersection check for non-magnifiable windows is needed when onWindowTransition," bug: "312624253" +} + +flag { + name: "magnification_always_draw_fullscreen_border" + namespace: "accessibility" + description: "Always draw fullscreen orange border in fullscreen magnification" + bug: "291891390" }
\ No newline at end of file diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig index 82067defd336..254f4f77c100 100644 --- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig +++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig @@ -77,3 +77,10 @@ flag { bug: "309593314" is_fixed_read_only: true } + +flag { + name: "letterbox_background_wallpaper" + namespace: "large_screen_experiences_app_compat" + description: "Whether the blurred letterbox wallpaper background is enabled by default" + bug: "297195682" +} diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index 4e8661652e85..63a2474e70c1 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -7,3 +7,10 @@ flag { bug: "320350734" is_fixed_read_only: true } + +flag { + name: "enable_desktop_windowing_mode" + namespace: "lse_desktop_experience" + description: "Enables desktop windowing" + bug: "304778354" +} diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig index 8b3bd974b3fa..3f483418c6b3 100644 --- a/core/java/android/window/flags/window_surfaces.aconfig +++ b/core/java/android/window/flags/window_surfaces.aconfig @@ -81,3 +81,14 @@ flag { is_fixed_read_only: true bug: "321263247" } + +flag { + namespace: "window_surfaces" + name: "enable_buffer_transform_hint_from_display" + description: "Always use display info to determine VRI's buffer transform hint" + is_fixed_read_only: true + bug: "301238858" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 86d3037b1612..29669d312b1b 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -96,6 +96,7 @@ import android.provider.Downloads; import android.provider.OpenableColumns; import android.provider.Settings; import android.service.chooser.ChooserTarget; +import android.service.chooser.Flags; import android.text.TextUtils; import android.util.AttributeSet; import android.util.HashedStringCache; @@ -2543,6 +2544,9 @@ public class ChooserActivity extends ResolverActivity implements @Override public boolean isComponentPinned(ComponentName name) { + if (Flags.legacyChooserPinningRemoval()) { + return false; + } return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false); } @@ -3147,6 +3151,10 @@ public class ChooserActivity extends ResolverActivity implements } private boolean shouldShowTargetDetails(TargetInfo ti) { + if (Flags.legacyChooserPinningRemoval()) { + // Never show the long press menu if we've removed pinning. + return false; + } ComponentName nearbyShare = getNearbySharingComponent(); // Suppress target details for nearby share to hide pin/unpin action boolean isNearbyShare = nearbyShare != null && nearbyShare.equals( diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java index 73914a2a99f6..4ef0a1baa4d1 100644 --- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java +++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java @@ -67,6 +67,8 @@ public class UnlaunchableAppActivity extends Activity mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); mTarget = intent.getParcelableExtra(Intent.EXTRA_INTENT, android.content.IntentSender.class); + String targetPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME); + final UserManager userManager = UserManager.get(this); if (mUserId == UserHandle.USER_NULL) { Log.wtf(TAG, "Invalid user id: " + mUserId + ". Stopping."); @@ -74,13 +76,20 @@ public class UnlaunchableAppActivity extends Activity return; } + if (android.os.Flags.allowPrivateProfile() + && !userManager.isManagedProfile(mUserId)) { + Log.e(TAG, "Unlaunchable activity for target package " + targetPackageName + + " called for a non-managed-profile " + mUserId); + finish(); + return; + } + if (mReason != UNLAUNCHABLE_REASON_QUIET_MODE) { Log.wtf(TAG, "Invalid unlaunchable type: " + mReason); finish(); return; } - String targetPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME); boolean showEmergencyCallButton = (targetPackageName != null && targetPackageName.equals( mTelecomManager.getDefaultDialerPackage(UserHandle.of(mUserId)))); diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java index 73df5e8e7b1b..5e89d06facd1 100644 --- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java +++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java @@ -421,6 +421,8 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, @NonNull private String[] mUsesStaticLibrariesSorted; + private boolean mAppMetadataFileInApk = false; + @NonNull public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath, @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp, @@ -1063,6 +1065,11 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, return memtagMode; } + @Override + public boolean isAppMetadataFileInApk() { + return mAppMetadataFileInApk; + } + @Nullable @Override public Bundle getMetaData() { @@ -2151,6 +2158,12 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, } @Override + public PackageImpl setAppMetadataFileInApk(boolean fileInApk) { + mAppMetadataFileInApk = fileInApk; + return this; + } + + @Override public PackageImpl setMetaData(@Nullable Bundle value) { metaData = value; return this; @@ -3264,6 +3277,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, dest.writeLong(this.mBooleans); dest.writeLong(this.mBooleans2); dest.writeBoolean(this.mAllowCrossUidActivitySwitchFromBelow); + dest.writeBoolean(this.mAppMetadataFileInApk); } public PackageImpl(Parcel in) { @@ -3426,6 +3440,7 @@ public class PackageImpl implements ParsedPackage, AndroidPackageInternal, this.mBooleans = in.readLong(); this.mBooleans2 = in.readLong(); this.mAllowCrossUidActivitySwitchFromBelow = in.readBoolean(); + this.mAppMetadataFileInApk = in.readBoolean(); assignDerivedFields(); assignDerivedFields2(); diff --git a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java index 66cfb69d7871..3c26a7c3eba3 100644 --- a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java +++ b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java @@ -127,4 +127,7 @@ public interface ParsedPackage extends AndroidPackage { ParsedPackage setDirectBootAware(boolean directBootAware); ParsedPackage setPersistent(boolean persistent); + + /** Retrieves whether the apk contains a app metadata file. */ + boolean isAppMetadataFileInApk(); } diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java index 5d185af17d48..5ab17a6b2b19 100644 --- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java @@ -133,6 +133,9 @@ public interface ParsingPackage { @Nullable SparseArray<int[]> splitDependencies ); + /** Sets whether the apk contains a app metadata file. */ + ParsingPackage setAppMetadataFileInApk(boolean fileInApk); + ParsingPackage setMetaData(Bundle metaData); ParsingPackage setForceQueryable(boolean forceQueryable); diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java index 2e6053d3d904..00c482722fa3 100644 --- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java +++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java @@ -46,6 +46,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.ConfigurationInfo; import android.content.pm.FeatureGroupInfo; import android.content.pm.FeatureInfo; +import android.content.pm.Flags; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.Property; @@ -163,6 +164,8 @@ public class ParsingPackageUtils { */ public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"; + public static final String APP_METADATA_FILE_NAME = "app.metadata"; + /** * Path prefix for apps on expanded storage */ @@ -636,6 +639,11 @@ public class ParsingPackageUtils { pkg.setSigningDetails(SigningDetails.UNKNOWN); } + if (Flags.aslInApkAppMetadataSource() + && ArrayUtils.contains(assets.list(""), APP_METADATA_FILE_NAME)) { + pkg.setAppMetadataFileInApk(true); + } + return input.success(pkg); } catch (Exception e) { return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, @@ -686,7 +694,8 @@ public class ParsingPackageUtils { */ private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath, String codePath, Resources res, XmlResourceParser parser, int flags, - boolean shouldSkipComponents) throws XmlPullParserException, IOException { + boolean shouldSkipComponents) + throws XmlPullParserException, IOException { final String splitName; final String pkgName; diff --git a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java index abe6c7c079c2..d9ac5a9fe47a 100644 --- a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,8 +37,11 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ILogger; +import com.android.internal.protolog.common.IProtoLog; import com.android.internal.protolog.common.IProtoLogGroup; import com.android.internal.protolog.common.LogDataType; +import com.android.internal.protolog.common.LogLevel; import com.android.internal.util.TraceBuffer; import java.io.File; @@ -48,52 +51,49 @@ import java.util.ArrayList; import java.util.TreeMap; import java.util.stream.Collectors; - /** * A service for the ProtoLog logging system. */ -public class BaseProtoLogImpl { - protected static final TreeMap<String, IProtoLogGroup> LOG_GROUPS = new TreeMap<>(); - - /** - * A runnable to update the cached output of {@link #isEnabled}. - * - * Must be invoked after every action that could change the result of {@link #isEnabled}, eg. - * starting / stopping proto log, or enabling / disabling log groups. - */ - public static Runnable sCacheUpdater = () -> { }; - - protected static void addLogGroupEnum(IProtoLogGroup[] config) { - for (IProtoLogGroup group : config) { - LOG_GROUPS.put(group.name(), group); - } - } +public class LegacyProtoLogImpl implements IProtoLog { + private final TreeMap<String, IProtoLogGroup> mLogGroups = new TreeMap<>(); + private static final int BUFFER_CAPACITY = 1024 * 1024; + private static final int PER_CHUNK_SIZE = 1024; private static final String TAG = "ProtoLog"; private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L; static final String PROTOLOG_VERSION = "1.0.0"; private static final int DEFAULT_PER_CHUNK_SIZE = 0; private final File mLogFile; - private final String mViewerConfigFilename; + private final String mLegacyViewerConfigFilename; private final TraceBuffer mBuffer; - protected final ProtoLogViewerConfigReader mViewerConfig; + private final LegacyProtoLogViewerConfigReader mViewerConfig; private final int mPerChunkSize; private boolean mProtoLogEnabled; private boolean mProtoLogEnabledLockFree; private final Object mProtoLogEnabledLock = new Object(); - @VisibleForTesting - public enum LogLevel { - DEBUG, VERBOSE, INFO, WARN, ERROR, WTF + public LegacyProtoLogImpl(String outputFile, String viewerConfigFilename) { + this(new File(outputFile), viewerConfigFilename, BUFFER_CAPACITY, + new LegacyProtoLogViewerConfigReader(), PER_CHUNK_SIZE); + } + + public LegacyProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity, + LegacyProtoLogViewerConfigReader viewerConfig, int perChunkSize) { + mLogFile = file; + mBuffer = new TraceBuffer(bufferCapacity); + mLegacyViewerConfigFilename = viewerConfigFilename; + mViewerConfig = viewerConfig; + mPerChunkSize = perChunkSize; } /** * Main log method, do not call directly. */ @VisibleForTesting - public void log(LogLevel level, IProtoLogGroup group, int messageHash, int paramsMask, + @Override + public void log(LogLevel level, IProtoLogGroup group, long messageHash, int paramsMask, @Nullable String messageString, Object[] args) { if (group.isLogToProto()) { logToProto(messageHash, paramsMask, args); @@ -103,7 +103,7 @@ public class BaseProtoLogImpl { } } - private void logToLogcat(String tag, LogLevel level, int messageHash, + private void logToLogcat(String tag, LogLevel level, long messageHash, @Nullable String messageString, Object[] args) { String message = null; if (messageString == null) { @@ -157,7 +157,7 @@ public class BaseProtoLogImpl { } } - private void logToProto(int messageHash, int paramsMask, Object[] args) { + private void logToProto(long messageHash, int paramsMask, Object[] args) { if (!isProtoEnabled()) { return; } @@ -219,20 +219,6 @@ public class BaseProtoLogImpl { } } - public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity, - ProtoLogViewerConfigReader viewerConfig) { - this(file, viewerConfigFilename, bufferCapacity, viewerConfig, DEFAULT_PER_CHUNK_SIZE); - } - - public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity, - ProtoLogViewerConfigReader viewerConfig, int perChunkSize) { - mLogFile = file; - mBuffer = new TraceBuffer(bufferCapacity); - mViewerConfigFilename = viewerConfigFilename; - mViewerConfig = viewerConfig; - mPerChunkSize = perChunkSize; - } - /** * Starts the logging a circular proto buffer. * @@ -248,7 +234,6 @@ public class BaseProtoLogImpl { mProtoLogEnabled = true; mProtoLogEnabledLockFree = true; } - sCacheUpdater.run(); } /** @@ -274,7 +259,6 @@ public class BaseProtoLogImpl { throw new IllegalStateException("logging enabled while waiting for flush."); } } - sCacheUpdater.run(); } /** @@ -284,11 +268,11 @@ public class BaseProtoLogImpl { return mProtoLogEnabledLockFree; } - protected int setLogging(boolean setTextLogging, boolean value, PrintWriter pw, + private int setLogging(boolean setTextLogging, boolean value, ILogger logger, String... groups) { for (int i = 0; i < groups.length; i++) { String group = groups[i]; - IProtoLogGroup g = LOG_GROUPS.get(group); + IProtoLogGroup g = mLogGroups.get(group); if (g != null) { if (setTextLogging) { g.setLogToLogcat(value); @@ -296,11 +280,10 @@ public class BaseProtoLogImpl { g.setLogToProto(value); } } else { - logAndPrintln(pw, "No IProtoLogGroup named " + group); + logger.log("No IProtoLogGroup named " + group); return -1; } } - sCacheUpdater.run(); return 0; } @@ -330,6 +313,7 @@ public class BaseProtoLogImpl { while ((arg = shell.getNextArg()) != null) { args.add(arg); } + final ILogger logger = (msg) -> logAndPrintln(pw, msg); String[] groups = args.toArray(new String[args.size()]); switch (cmd) { case "start": @@ -342,14 +326,14 @@ public class BaseProtoLogImpl { logAndPrintln(pw, getStatus()); return 0; case "enable": - return setLogging(false, true, pw, groups); + return setLogging(false, true, logger, groups); case "enable-text": - mViewerConfig.loadViewerConfig(pw, mViewerConfigFilename); - return setLogging(true, true, pw, groups); + mViewerConfig.loadViewerConfig(logger, mLegacyViewerConfigFilename); + return setLogging(true, true, logger, groups); case "disable": - return setLogging(false, false, pw, groups); + return setLogging(false, false, logger, groups); case "disable-text": - return setLogging(true, false, pw, groups); + return setLogging(true, false, logger, groups); default: return unknownCommand(pw); } @@ -362,12 +346,12 @@ public class BaseProtoLogImpl { return "ProtoLog status: " + ((isProtoEnabled()) ? "Enabled" : "Disabled") + "\nEnabled log groups: \n Proto: " - + LOG_GROUPS.values().stream().filter( - it -> it.isEnabled() && it.isLogToProto()) + + mLogGroups.values().stream().filter( + it -> it.isEnabled() && it.isLogToProto()) .map(IProtoLogGroup::name).collect(Collectors.joining(" ")) + "\n Logcat: " - + LOG_GROUPS.values().stream().filter( - it -> it.isEnabled() && it.isLogToLogcat()) + + mLogGroups.values().stream().filter( + it -> it.isEnabled() && it.isLogToLogcat()) .map(IProtoLogGroup::name).collect(Collectors.joining(" ")) + "\nLogging definitions loaded: " + mViewerConfig.knownViewerStringsNumber(); } @@ -393,5 +377,26 @@ public class BaseProtoLogImpl { pw.flush(); } } + + /** + * Start text logging + * @param groups Groups to start text logging for + * @param logger A logger to write status updates to + * @return status code + */ + public int startLoggingToLogcat(String[] groups, ILogger logger) { + mViewerConfig.loadViewerConfig(logger, mLegacyViewerConfigFilename); + return setLogging(true /* setTextLogging */, true, logger, groups); + } + + /** + * Stop text logging + * @param groups Groups to start text logging for + * @param logger A logger to write status updates to + * @return status code + */ + public int stopLoggingToLogcat(String[] groups, ILogger logger) { + return setLogging(true /* setTextLogging */, false, logger, groups); + } } diff --git a/core/java/com/android/internal/protolog/LegacyProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/LegacyProtoLogViewerConfigReader.java new file mode 100644 index 000000000000..1833410950ba --- /dev/null +++ b/core/java/com/android/internal/protolog/LegacyProtoLogViewerConfigReader.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2020 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.internal.protolog; + +import com.android.internal.protolog.common.ILogger; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; +import java.util.zip.GZIPInputStream; + +/** + * Handles loading and parsing of ProtoLog viewer configuration. + */ +public class LegacyProtoLogViewerConfigReader { + + private static final String TAG = "ProtoLogViewerConfigReader"; + private Map<Long, String> mLogMessageMap = null; + + /** Returns message format string for its hash or null if unavailable. */ + public synchronized String getViewerString(long messageHash) { + if (mLogMessageMap != null) { + return mLogMessageMap.get(messageHash); + } else { + return null; + } + } + + /** + * Reads the specified viewer configuration file. Does nothing if the config is already loaded. + */ + public synchronized void loadViewerConfig(ILogger logger, String viewerConfigFilename) { + try { + loadViewerConfig(new GZIPInputStream(new FileInputStream(viewerConfigFilename))); + logger.log("Loaded " + mLogMessageMap.size() + + " log definitions from " + viewerConfigFilename); + } catch (FileNotFoundException e) { + logger.log("Unable to load log definitions: File " + + viewerConfigFilename + " not found." + e); + } catch (IOException e) { + logger.log("Unable to load log definitions: IOException while reading " + + viewerConfigFilename + ". " + e); + } catch (JSONException e) { + logger.log("Unable to load log definitions: JSON parsing exception while reading " + + viewerConfigFilename + ". " + e); + } + } + + /** + * Reads the specified viewer configuration input stream. + * Does nothing if the config is already loaded. + */ + public synchronized void loadViewerConfig(InputStream viewerConfigInputStream) + throws IOException, JSONException { + if (mLogMessageMap != null) { + return; + } + InputStreamReader config = new InputStreamReader(viewerConfigInputStream); + BufferedReader reader = new BufferedReader(config); + StringBuilder builder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + builder.append(line).append('\n'); + } + reader.close(); + JSONObject json = new JSONObject(builder.toString()); + JSONObject messages = json.getJSONObject("messages"); + + mLogMessageMap = new TreeMap<>(); + Iterator it = messages.keys(); + while (it.hasNext()) { + String key = (String) it.next(); + try { + long hash = Long.parseLong(key); + JSONObject val = messages.getJSONObject(key); + String msg = val.getString("message"); + mLogMessageMap.put(hash, msg); + } catch (NumberFormatException expected) { + // Not a messageHash - skip it + } + } + } + + /** + * Returns the number of loaded log definitions kept in memory. + */ + public synchronized int knownViewerStringsNumber() { + if (mLogMessageMap != null) { + return mLogMessageMap.size(); + } + return 0; + } + +} diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java new file mode 100644 index 000000000000..53062d837cfa --- /dev/null +++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java @@ -0,0 +1,559 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.protolog; + +import static perfetto.protos.PerfettoTrace.InternedData.PROTOLOG_STACKTRACE; +import static perfetto.protos.PerfettoTrace.InternedData.PROTOLOG_STRING_ARGS; +import static perfetto.protos.PerfettoTrace.InternedString.IID; +import static perfetto.protos.PerfettoTrace.InternedString.STR; +import static perfetto.protos.PerfettoTrace.ProtoLogMessage.BOOLEAN_PARAMS; +import static perfetto.protos.PerfettoTrace.ProtoLogMessage.DOUBLE_PARAMS; +import static perfetto.protos.PerfettoTrace.ProtoLogMessage.STACKTRACE_IID; +import static perfetto.protos.PerfettoTrace.ProtoLogMessage.MESSAGE_ID; +import static perfetto.protos.PerfettoTrace.ProtoLogMessage.SINT64_PARAMS; +import static perfetto.protos.PerfettoTrace.ProtoLogMessage.STR_PARAM_IIDS; +import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.GROUPS; +import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.Group.ID; +import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.Group.NAME; +import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.Group.TAG; +import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MESSAGES; +import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.GROUP_ID; +import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.LEVEL; +import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.MESSAGE; +import static perfetto.protos.PerfettoTrace.TracePacket.INTERNED_DATA; +import static perfetto.protos.PerfettoTrace.TracePacket.PROTOLOG_MESSAGE; +import static perfetto.protos.PerfettoTrace.TracePacket.PROTOLOG_VIEWER_CONFIG; +import static perfetto.protos.PerfettoTrace.TracePacket.SEQUENCE_FLAGS; +import static perfetto.protos.PerfettoTrace.TracePacket.SEQ_INCREMENTAL_STATE_CLEARED; +import static perfetto.protos.PerfettoTrace.TracePacket.SEQ_NEEDS_INCREMENTAL_STATE; +import static perfetto.protos.PerfettoTrace.TracePacket.TIMESTAMP; + +import android.annotation.Nullable; +import android.os.ShellCommand; +import android.os.SystemClock; +import android.os.Trace; +import android.text.TextUtils; +import android.tracing.perfetto.DataSourceParams; +import android.tracing.perfetto.InitArguments; +import android.tracing.perfetto.Producer; +import android.tracing.perfetto.TracingContext; +import android.util.LongArray; +import android.util.Slog; +import android.util.proto.ProtoInputStream; +import android.util.proto.ProtoOutputStream; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.ILogger; +import com.android.internal.protolog.common.IProtoLog; +import com.android.internal.protolog.common.IProtoLogGroup; +import com.android.internal.protolog.common.LogDataType; +import com.android.internal.protolog.common.LogLevel; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.atomic.AtomicInteger; + +import perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData; + +/** + * A service for the ProtoLog logging system. + */ +public class PerfettoProtoLogImpl implements IProtoLog { + private final TreeMap<String, IProtoLogGroup> mLogGroups = new TreeMap<>(); + private static final String LOG_TAG = "ProtoLog"; + private final AtomicInteger mTracingInstances = new AtomicInteger(); + + private final ProtoLogDataSource mDataSource = new ProtoLogDataSource( + this.mTracingInstances::incrementAndGet, + this::dumpTransitionTraceConfig, + this.mTracingInstances::decrementAndGet + ); + private final ProtoLogViewerConfigReader mViewerConfigReader; + private final ViewerConfigInputStreamProvider mViewerConfigInputStreamProvider; + + public PerfettoProtoLogImpl(String viewerConfigFilePath) { + this(() -> { + try { + return new ProtoInputStream(new FileInputStream(viewerConfigFilePath)); + } catch (FileNotFoundException e) { + Slog.w(LOG_TAG, "Failed to load viewer config file " + viewerConfigFilePath, e); + return null; + } + }); + } + + public PerfettoProtoLogImpl(ViewerConfigInputStreamProvider viewerConfigInputStreamProvider) { + this(viewerConfigInputStreamProvider, + new ProtoLogViewerConfigReader(viewerConfigInputStreamProvider)); + } + + @VisibleForTesting + public PerfettoProtoLogImpl( + ViewerConfigInputStreamProvider viewerConfigInputStreamProvider, + ProtoLogViewerConfigReader viewerConfigReader + ) { + Producer.init(InitArguments.DEFAULTS); + mDataSource.register(DataSourceParams.DEFAULTS); + this.mViewerConfigInputStreamProvider = viewerConfigInputStreamProvider; + this.mViewerConfigReader = viewerConfigReader; + } + + /** + * Main log method, do not call directly. + */ + @VisibleForTesting + @Override + public void log(LogLevel level, IProtoLogGroup group, long messageHash, int paramsMask, + @Nullable String messageString, Object[] args) { + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "log"); + + long tsNanos = SystemClock.elapsedRealtimeNanos(); + try { + logToProto(level, group.name(), messageHash, paramsMask, args, tsNanos); + if (group.isLogToLogcat()) { + logToLogcat(group.getTag(), level, messageHash, messageString, args); + } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + } + } + + private void dumpTransitionTraceConfig() { + ProtoInputStream pis = mViewerConfigInputStreamProvider.getInputStream(); + + if (pis == null) { + Slog.w(LOG_TAG, "Failed to get viewer input stream."); + return; + } + + mDataSource.trace(ctx -> { + final ProtoOutputStream os = ctx.newTracePacket(); + + os.write(TIMESTAMP, SystemClock.elapsedRealtimeNanos()); + + final long outProtologViewerConfigToken = os.start(PROTOLOG_VIEWER_CONFIG); + while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + if (pis.getFieldNumber() == (int) MESSAGES) { + final long inMessageToken = pis.start(MESSAGES); + final long outMessagesToken = os.start(MESSAGES); + + while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + switch (pis.getFieldNumber()) { + case (int) MessageData.MESSAGE_ID: + os.write(MessageData.MESSAGE_ID, + pis.readLong(MessageData.MESSAGE_ID)); + break; + case (int) MESSAGE: + os.write(MESSAGE, pis.readString(MESSAGE)); + break; + case (int) LEVEL: + os.write(LEVEL, pis.readInt(LEVEL)); + break; + case (int) GROUP_ID: + os.write(GROUP_ID, pis.readInt(GROUP_ID)); + break; + default: + throw new RuntimeException( + "Unexpected field id " + pis.getFieldNumber()); + } + } + + pis.end(inMessageToken); + os.end(outMessagesToken); + } + + if (pis.getFieldNumber() == (int) GROUPS) { + final long inGroupToken = pis.start(GROUPS); + final long outGroupToken = os.start(GROUPS); + + while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + switch (pis.getFieldNumber()) { + case (int) ID: + int id = pis.readInt(ID); + os.write(ID, id); + break; + case (int) NAME: + String name = pis.readString(NAME); + os.write(NAME, name); + break; + case (int) TAG: + String tag = pis.readString(TAG); + os.write(TAG, tag); + break; + default: + throw new RuntimeException( + "Unexpected field id " + pis.getFieldNumber()); + } + } + + pis.end(inGroupToken); + os.end(outGroupToken); + } + } + + os.end(outProtologViewerConfigToken); + + ctx.flush(); + }); + + mDataSource.flush(); + } + + private void logToLogcat(String tag, LogLevel level, long messageHash, + @Nullable String messageString, Object[] args) { + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "logToLogcat"); + try { + doLogToLogcat(tag, level, messageHash, messageString, args); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + } + } + + private void doLogToLogcat(String tag, LogLevel level, long messageHash, + @androidx.annotation.Nullable String messageString, Object[] args) { + String message = null; + if (messageString == null) { + messageString = mViewerConfigReader.getViewerString(messageHash); + } + if (messageString != null) { + if (args != null) { + try { + message = TextUtils.formatSimple(messageString, args); + } catch (Exception ex) { + Slog.w(LOG_TAG, "Invalid ProtoLog format string.", ex); + } + } else { + message = messageString; + } + } + if (message == null) { + StringBuilder builder = new StringBuilder("UNKNOWN MESSAGE (" + messageHash + ")"); + for (Object o : args) { + builder.append(" ").append(o); + } + message = builder.toString(); + } + passToLogcat(tag, level, message); + } + + /** + * SLog wrapper. + */ + @VisibleForTesting + public void passToLogcat(String tag, LogLevel level, String message) { + switch (level) { + case DEBUG: + Slog.d(tag, message); + break; + case VERBOSE: + Slog.v(tag, message); + break; + case INFO: + Slog.i(tag, message); + break; + case WARN: + Slog.w(tag, message); + break; + case ERROR: + Slog.e(tag, message); + break; + case WTF: + Slog.wtf(tag, message); + break; + } + } + + private void logToProto(LogLevel level, String groupName, long messageHash, int paramsMask, + Object[] args, long tsNanos) { + if (!isProtoEnabled()) { + return; + } + + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "logToProto"); + try { + doLogToProto(level, groupName, messageHash, paramsMask, args, tsNanos); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); + } + } + + private void doLogToProto(LogLevel level, String groupName, long messageHash, int paramsMask, + Object[] args, long tsNanos) { + mDataSource.trace(ctx -> { + final ProtoLogDataSource.TlsState tlsState = ctx.getCustomTlsState(); + final LogLevel logFrom = tlsState.getLogFromLevel(groupName); + + if (level.ordinal() < logFrom.ordinal()) { + return; + } + + if (args != null) { + // Intern all string params before creating the trace packet for the proto + // message so that the interned strings appear before in the trace to make the + // trace processing easier. + int argIndex = 0; + for (Object o : args) { + int type = LogDataType.bitmaskToLogDataType(paramsMask, argIndex); + if (type == LogDataType.STRING) { + internStringArg(ctx, o.toString()); + } + argIndex++; + } + } + + int internedStacktrace = 0; + if (tlsState.getShouldCollectStacktrace(groupName)) { + // Intern stackstraces before creating the trace packet for the proto message so + // that the interned stacktrace strings appear before in the trace to make the + // trace processing easier. + String stacktrace = collectStackTrace(); + internedStacktrace = internStacktraceString(ctx, stacktrace); + } + + final ProtoOutputStream os = ctx.newTracePacket(); + os.write(TIMESTAMP, tsNanos); + long token = os.start(PROTOLOG_MESSAGE); + os.write(MESSAGE_ID, messageHash); + + boolean needsIncrementalState = false; + + if (args != null) { + + int argIndex = 0; + LongArray longParams = new LongArray(); + ArrayList<Double> doubleParams = new ArrayList<>(); + ArrayList<Boolean> booleanParams = new ArrayList<>(); + for (Object o : args) { + int type = LogDataType.bitmaskToLogDataType(paramsMask, argIndex); + try { + switch (type) { + case LogDataType.STRING: + final int internedStringId = internStringArg(ctx, o.toString()); + os.write(STR_PARAM_IIDS, internedStringId); + needsIncrementalState = true; + break; + case LogDataType.LONG: + longParams.add(((Number) o).longValue()); + break; + case LogDataType.DOUBLE: + doubleParams.add(((Number) o).doubleValue()); + break; + case LogDataType.BOOLEAN: + booleanParams.add((boolean) o); + break; + } + } catch (ClassCastException ex) { + Slog.e(LOG_TAG, "Invalid ProtoLog paramsMask", ex); + } + argIndex++; + } + + for (int i = 0; i < longParams.size(); ++i) { + os.write(SINT64_PARAMS, longParams.get(i)); + } + doubleParams.forEach(it -> os.write(DOUBLE_PARAMS, it)); + // Converting booleans to int because Perfetto doesn't yet support repeated + // booleans, so we use a repeated integers instead (b/313651412). + booleanParams.forEach(it -> os.write(BOOLEAN_PARAMS, it ? 1 : 0)); + } + + if (tlsState.getShouldCollectStacktrace(groupName)) { + os.write(STACKTRACE_IID, internedStacktrace); + } + + os.end(token); + + if (needsIncrementalState) { + os.write(SEQUENCE_FLAGS, SEQ_NEEDS_INCREMENTAL_STATE); + } + + }); + } + + private static final int STACK_SIZE_TO_PROTO_LOG_ENTRY_CALL = 12; + + private String collectStackTrace() { + StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + StringWriter sw = new StringWriter(); + try (PrintWriter pw = new PrintWriter(sw)) { + for (int i = STACK_SIZE_TO_PROTO_LOG_ENTRY_CALL; i < stackTrace.length; ++i) { + pw.println("\tat " + stackTrace[i]); + } + } + + return sw.toString(); + } + + private int internStacktraceString(TracingContext<ProtoLogDataSource.Instance, + ProtoLogDataSource.TlsState, + ProtoLogDataSource.IncrementalState> ctx, + String stacktrace) { + final ProtoLogDataSource.IncrementalState incrementalState = ctx.getIncrementalState(); + return internString(ctx, incrementalState.stacktraceInterningMap, + PROTOLOG_STACKTRACE, stacktrace); + } + + private int internStringArg( + TracingContext<ProtoLogDataSource.Instance, + ProtoLogDataSource.TlsState, + ProtoLogDataSource.IncrementalState> ctx, + String string + ) { + final ProtoLogDataSource.IncrementalState incrementalState = ctx.getIncrementalState(); + return internString(ctx, incrementalState.argumentInterningMap, + PROTOLOG_STRING_ARGS, string); + } + + private int internString( + TracingContext<ProtoLogDataSource.Instance, + ProtoLogDataSource.TlsState, + ProtoLogDataSource.IncrementalState> ctx, + Map<String, Integer> internMap, + long fieldId, + String string + ) { + final ProtoLogDataSource.IncrementalState incrementalState = ctx.getIncrementalState(); + + if (!incrementalState.clearReported) { + final ProtoOutputStream os = ctx.newTracePacket(); + os.write(SEQUENCE_FLAGS, SEQ_INCREMENTAL_STATE_CLEARED); + incrementalState.clearReported = true; + } + + if (!internMap.containsKey(string)) { + final int internedIndex = internMap.size() + 1; + internMap.put(string, internedIndex); + + final ProtoOutputStream os = ctx.newTracePacket(); + final long token = os.start(INTERNED_DATA); + final long innerToken = os.start(fieldId); + os.write(IID, internedIndex); + os.write(STR, string.getBytes()); + os.end(innerToken); + os.end(token); + } + + return internMap.get(string); + } + + /** + * Responds to a shell command. + */ + public int onShellCommand(ShellCommand shell) { + PrintWriter pw = shell.getOutPrintWriter(); + String cmd = shell.getNextArg(); + if (cmd == null) { + return unknownCommand(pw); + } + ArrayList<String> args = new ArrayList<>(); + String arg; + while ((arg = shell.getNextArg()) != null) { + args.add(arg); + } + final ILogger logger = (msg) -> logAndPrintln(pw, msg); + String[] groups = args.toArray(new String[args.size()]); + switch (cmd) { + case "enable-text": + return this.startLoggingToLogcat(groups, logger); + case "disable-text": + return this.stopLoggingToLogcat(groups, logger); + default: + return unknownCommand(pw); + } + } + + private int unknownCommand(PrintWriter pw) { + pw.println("Unknown command"); + pw.println("Window manager logging options:"); + pw.println(" enable-text [group...]: Enable logcat logging for given groups"); + pw.println(" disable-text [group...]: Disable logcat logging for given groups"); + return -1; + } + + /** + * Returns {@code true} iff logging to proto is enabled. + */ + public boolean isProtoEnabled() { + return mTracingInstances.get() > 0; + } + + /** + * Start text logging + * @param groups Groups to start text logging for + * @param logger A logger to write status updates to + * @return status code + */ + public int startLoggingToLogcat(String[] groups, ILogger logger) { + mViewerConfigReader.loadViewerConfig(logger); + return setTextLogging(true, logger, groups); + } + + /** + * Stop text logging + * @param groups Groups to start text logging for + * @param logger A logger to write status updates to + * @return status code + */ + public int stopLoggingToLogcat(String[] groups, ILogger logger) { + mViewerConfigReader.unloadViewerConfig(); + return setTextLogging(false, logger, groups); + } + + /** + * Start logging the stack trace of the when the log message happened for target groups + * @return status code + */ + public int startLoggingStackTrace(String[] groups, ILogger logger) { + return -1; + } + + /** + * Stop logging the stack trace of the when the log message happened for target groups + * @return status code + */ + public int stopLoggingStackTrace() { + return -1; + } + + private int setTextLogging(boolean value, ILogger logger, String... groups) { + for (int i = 0; i < groups.length; i++) { + String group = groups[i]; + IProtoLogGroup g = mLogGroups.get(group); + if (g != null) { + g.setLogToLogcat(value); + } else { + logger.log("No IProtoLogGroup named " + group); + return -1; + } + } + return 0; + } + + static void logAndPrintln(@Nullable PrintWriter pw, String msg) { + Slog.i(LOG_TAG, msg); + if (pw != null) { + pw.println(msg); + pw.flush(); + } + } +} + diff --git a/core/java/com/android/internal/protolog/ProtoLogDataSource.java b/core/java/com/android/internal/protolog/ProtoLogDataSource.java new file mode 100644 index 000000000000..a8ff75d6595e --- /dev/null +++ b/core/java/com/android/internal/protolog/ProtoLogDataSource.java @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2023 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.internal.protolog; + +import static perfetto.protos.PerfettoTrace.DataSourceConfig.PROTOLOG_CONFIG; +import static perfetto.protos.PerfettoTrace.ProtoLogConfig.GROUP_OVERRIDES; +import static perfetto.protos.PerfettoTrace.ProtoLogConfig.TRACING_MODE; +import static perfetto.protos.PerfettoTrace.ProtoLogGroup.COLLECT_STACKTRACE; +import static perfetto.protos.PerfettoTrace.ProtoLogGroup.LOG_FROM; +import static perfetto.protos.PerfettoTrace.ProtoLogGroup.GROUP_NAME; + +import android.tracing.perfetto.CreateIncrementalStateArgs; +import android.tracing.perfetto.CreateTlsStateArgs; +import android.tracing.perfetto.DataSource; +import android.tracing.perfetto.DataSourceInstance; +import android.tracing.perfetto.FlushCallbackArguments; +import android.tracing.perfetto.StartCallbackArguments; +import android.tracing.perfetto.StopCallbackArguments; +import android.util.proto.ProtoInputStream; +import android.util.proto.WireTypeMismatchException; + +import com.android.internal.protolog.common.LogLevel; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import perfetto.protos.PerfettoTrace; + +public class ProtoLogDataSource extends DataSource<ProtoLogDataSource.Instance, + ProtoLogDataSource.TlsState, + ProtoLogDataSource.IncrementalState> { + + private final Runnable mOnStart; + private final Runnable mOnFlush; + private final Runnable mOnStop; + + public ProtoLogDataSource(Runnable onStart, Runnable onFlush, Runnable onStop) { + super("android.protolog"); + this.mOnStart = onStart; + this.mOnFlush = onFlush; + this.mOnStop = onStop; + } + + @Override + public Instance createInstance(ProtoInputStream configStream, int instanceIndex) { + ProtoLogConfig config = null; + + try { + while (configStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + try { + if (configStream.getFieldNumber() == (int) PROTOLOG_CONFIG) { + if (config != null) { + throw new RuntimeException("ProtoLog config already set in loop"); + } + config = readProtoLogConfig(configStream); + } + } catch (WireTypeMismatchException e) { + throw new RuntimeException("Failed to parse ProtoLog DataSource config", e); + } + } + } catch (IOException e) { + throw new RuntimeException("Failed to read ProtoLog DataSource config", e); + } + + if (config == null) { + // No config found + config = ProtoLogConfig.DEFAULT; + } + + return new Instance( + this, instanceIndex, config, mOnStart, mOnFlush, mOnStop); + } + + @Override + public TlsState createTlsState(CreateTlsStateArgs<Instance> args) { + try (Instance dsInstance = args.getDataSourceInstanceLocked()) { + if (dsInstance == null) { + // Datasource instance has been removed + return new TlsState(ProtoLogConfig.DEFAULT); + } + return new TlsState(dsInstance.mConfig); + } + } + + @Override + public IncrementalState createIncrementalState(CreateIncrementalStateArgs<Instance> args) { + return new IncrementalState(); + } + + public static class TlsState { + private final ProtoLogConfig mConfig; + + private TlsState(ProtoLogConfig config) { + this.mConfig = config; + } + + /** + * Get the log from level for a group. + * @param groupTag The tag of the group to get the log from level. + * @return The lowest LogLevel (inclusive) to log message from. + */ + public LogLevel getLogFromLevel(String groupTag) { + return getConfigFor(groupTag).logFrom; + } + + /** + * Get if the stacktrace for the log message should be collected for this group. + * @param groupTag The tag of the group to get whether or not a stacktrace was requested. + * @return True iff a stacktrace was requested to be collected from this group in the + * tracing config. + */ + public boolean getShouldCollectStacktrace(String groupTag) { + return getConfigFor(groupTag).collectStackTrace; + } + + private GroupConfig getConfigFor(String groupTag) { + return mConfig.getConfigFor(groupTag); + } + } + + public static class IncrementalState { + public final Map<String, Integer> argumentInterningMap = new HashMap<>(); + public final Map<String, Integer> stacktraceInterningMap = new HashMap<>(); + public boolean clearReported = false; + } + + private static class ProtoLogConfig { + private final LogLevel mDefaultLogFromLevel; + private final Map<String, GroupConfig> mGroupConfigs; + + private static final ProtoLogConfig DEFAULT = + new ProtoLogConfig(LogLevel.WTF, new HashMap<>()); + + private ProtoLogConfig( + LogLevel defaultLogFromLevel, Map<String, GroupConfig> groupConfigs) { + this.mDefaultLogFromLevel = defaultLogFromLevel; + this.mGroupConfigs = groupConfigs; + } + + private GroupConfig getConfigFor(String groupTag) { + return mGroupConfigs.getOrDefault(groupTag, getDefaultGroupConfig()); + } + + private GroupConfig getDefaultGroupConfig() { + return new GroupConfig(mDefaultLogFromLevel, false); + } + } + + public static class GroupConfig { + public final LogLevel logFrom; + public final boolean collectStackTrace; + + public GroupConfig(LogLevel logFromLevel, boolean collectStackTrace) { + this.logFrom = logFromLevel; + this.collectStackTrace = collectStackTrace; + } + } + + private ProtoLogConfig readProtoLogConfig(ProtoInputStream configStream) + throws IOException { + final long config_token = configStream.start(PROTOLOG_CONFIG); + + LogLevel defaultLogFromLevel = LogLevel.WTF; + final Map<String, GroupConfig> groupConfigs = new HashMap<>(); + + while (configStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + if (configStream.getFieldNumber() == (int) TRACING_MODE) { + int tracingMode = configStream.readInt(TRACING_MODE); + switch (tracingMode) { + case PerfettoTrace.ProtoLogConfig.DEFAULT: + break; + case PerfettoTrace.ProtoLogConfig.ENABLE_ALL: + defaultLogFromLevel = LogLevel.DEBUG; + break; + default: + throw new RuntimeException("Unhandled ProtoLog tracing mode type"); + } + } + if (configStream.getFieldNumber() == (int) GROUP_OVERRIDES) { + final long group_overrides_token = configStream.start(GROUP_OVERRIDES); + + String tag = null; + LogLevel logFromLevel = defaultLogFromLevel; + boolean collectStackTrace = false; + while (configStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + if (configStream.getFieldNumber() == (int) GROUP_NAME) { + tag = configStream.readString(GROUP_NAME); + } + if (configStream.getFieldNumber() == (int) LOG_FROM) { + final int logFromInt = configStream.readInt(LOG_FROM); + switch (logFromInt) { + case (PerfettoTrace.PROTOLOG_LEVEL_DEBUG): { + logFromLevel = LogLevel.DEBUG; + break; + } + case (PerfettoTrace.PROTOLOG_LEVEL_VERBOSE): { + logFromLevel = LogLevel.VERBOSE; + break; + } + case (PerfettoTrace.PROTOLOG_LEVEL_INFO): { + logFromLevel = LogLevel.INFO; + break; + } + case (PerfettoTrace.PROTOLOG_LEVEL_WARN): { + logFromLevel = LogLevel.WARN; + break; + } + case (PerfettoTrace.PROTOLOG_LEVEL_ERROR): { + logFromLevel = LogLevel.ERROR; + break; + } + case (PerfettoTrace.PROTOLOG_LEVEL_WTF): { + logFromLevel = LogLevel.WTF; + break; + } + default: { + throw new RuntimeException("Unhandled log level"); + } + } + } + if (configStream.getFieldNumber() == (int) COLLECT_STACKTRACE) { + collectStackTrace = configStream.readBoolean(COLLECT_STACKTRACE); + } + } + + if (tag == null) { + throw new RuntimeException("Failed to decode proto config. " + + "Got a group override without a group tag."); + } + + groupConfigs.put(tag, new GroupConfig(logFromLevel, collectStackTrace)); + + configStream.end(group_overrides_token); + } + } + + configStream.end(config_token); + + return new ProtoLogConfig(defaultLogFromLevel, groupConfigs); + } + + public static class Instance extends DataSourceInstance { + + private final Runnable mOnStart; + private final Runnable mOnFlush; + private final Runnable mOnStop; + private final ProtoLogConfig mConfig; + + public Instance( + DataSource<Instance, TlsState, IncrementalState> dataSource, + int instanceIdx, + ProtoLogConfig config, + Runnable onStart, + Runnable onFlush, + Runnable onStop + ) { + super(dataSource, instanceIdx); + this.mOnStart = onStart; + this.mOnFlush = onFlush; + this.mOnStop = onStop; + this.mConfig = config; + } + + @Override + public void onStart(StartCallbackArguments args) { + this.mOnStart.run(); + } + + @Override + public void onFlush(FlushCallbackArguments args) { + this.mOnFlush.run(); + } + + @Override + public void onStop(StopCallbackArguments args) { + this.mOnStop.run(); + } + } +} diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java index 527cfddf6d8e..78bed9478d84 100644 --- a/core/java/com/android/internal/protolog/ProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java @@ -16,30 +16,35 @@ package com.android.internal.protolog; +import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_OUTPUT_FILE_PATH; +import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_VIEWER_CONFIG_PATH; +import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH; + import android.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.protolog.common.IProtoLog; import com.android.internal.protolog.common.IProtoLogGroup; - -import java.io.File; +import com.android.internal.protolog.common.LogLevel; +import com.android.internal.protolog.common.ProtoLogToolInjected; /** * A service for the ProtoLog logging system. */ -public class ProtoLogImpl extends BaseProtoLogImpl { - private static final int BUFFER_CAPACITY = 1024 * 1024; - private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.winscope"; - private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz"; - private static final int PER_CHUNK_SIZE = 1024; +public class ProtoLogImpl { + private static IProtoLog sServiceInstance = null; - private static ProtoLogImpl sServiceInstance = null; + @ProtoLogToolInjected(VIEWER_CONFIG_PATH) + private static String sViewerConfigPath; - static { - addLogGroupEnum(ProtoLogGroup.values()); - } + @ProtoLogToolInjected(LEGACY_VIEWER_CONFIG_PATH) + private static String sLegacyViewerConfigPath; + + @ProtoLogToolInjected(LEGACY_OUTPUT_FILE_PATH) + private static String sLegacyOutputFilePath; /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ - public static void d(IProtoLogGroup group, int messageHash, int paramsMask, + public static void d(IProtoLogGroup group, long messageHash, int paramsMask, @Nullable String messageString, Object... args) { getSingleInstance() @@ -47,7 +52,7 @@ public class ProtoLogImpl extends BaseProtoLogImpl { } /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ - public static void v(IProtoLogGroup group, int messageHash, int paramsMask, + public static void v(IProtoLogGroup group, long messageHash, int paramsMask, @Nullable String messageString, Object... args) { getSingleInstance().log(LogLevel.VERBOSE, group, messageHash, paramsMask, messageString, @@ -55,21 +60,21 @@ public class ProtoLogImpl extends BaseProtoLogImpl { } /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ - public static void i(IProtoLogGroup group, int messageHash, int paramsMask, + public static void i(IProtoLogGroup group, long messageHash, int paramsMask, @Nullable String messageString, Object... args) { getSingleInstance().log(LogLevel.INFO, group, messageHash, paramsMask, messageString, args); } /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ - public static void w(IProtoLogGroup group, int messageHash, int paramsMask, + public static void w(IProtoLogGroup group, long messageHash, int paramsMask, @Nullable String messageString, Object... args) { getSingleInstance().log(LogLevel.WARN, group, messageHash, paramsMask, messageString, args); } /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ - public static void e(IProtoLogGroup group, int messageHash, int paramsMask, + public static void e(IProtoLogGroup group, long messageHash, int paramsMask, @Nullable String messageString, Object... args) { getSingleInstance() @@ -77,40 +82,36 @@ public class ProtoLogImpl extends BaseProtoLogImpl { } /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ - public static void wtf(IProtoLogGroup group, int messageHash, int paramsMask, + public static void wtf(IProtoLogGroup group, long messageHash, int paramsMask, @Nullable String messageString, Object... args) { getSingleInstance().log(LogLevel.WTF, group, messageHash, paramsMask, messageString, args); } - /** Returns true iff logging is enabled for the given {@code IProtoLogGroup}. */ public static boolean isEnabled(IProtoLogGroup group) { - return group.isLogToLogcat() - || (group.isLogToProto() && getSingleInstance().isProtoEnabled()); + // TODO: Implement for performance reasons, with optional level parameter? + return true; } /** * Returns the single instance of the ProtoLogImpl singleton class. */ - public static synchronized ProtoLogImpl getSingleInstance() { + public static synchronized IProtoLog getSingleInstance() { if (sServiceInstance == null) { - sServiceInstance = new ProtoLogImpl( - new File(LOG_FILENAME) - , BUFFER_CAPACITY - , new ProtoLogViewerConfigReader() - , PER_CHUNK_SIZE); + if (android.tracing.Flags.perfettoProtolog()) { + sServiceInstance = + new PerfettoProtoLogImpl(sViewerConfigPath); + } else { + sServiceInstance = + new LegacyProtoLogImpl(sLegacyOutputFilePath, sLegacyViewerConfigPath); + } } return sServiceInstance; } @VisibleForTesting - public static synchronized void setSingleInstance(@Nullable ProtoLogImpl instance) { + public static synchronized void setSingleInstance(@Nullable IProtoLog instance) { sServiceInstance = instance; } - - public ProtoLogImpl(File logFile, int bufferCapacity, - ProtoLogViewerConfigReader viewConfigReader, int perChunkSize) { - super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader, perChunkSize); - } } diff --git a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java index aa30a7723ad9..3c206acf7c0f 100644 --- a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java +++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java @@ -1,125 +1,93 @@ -/* - * Copyright (C) 2020 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.internal.protolog; -import android.annotation.Nullable; -import android.util.Slog; +import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MESSAGES; +import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.MESSAGE; +import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.MESSAGE_ID; + +import android.util.proto.ProtoInputStream; -import org.json.JSONException; -import org.json.JSONObject; +import com.android.internal.protolog.common.ILogger; -import java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.util.Iterator; import java.util.Map; -import java.util.TreeMap; -import java.util.zip.GZIPInputStream; -/** - * Handles loading and parsing of ProtoLog viewer configuration. - */ public class ProtoLogViewerConfigReader { - private static final String TAG = "ProtoLogViewerConfigReader"; - private Map<Integer, String> mLogMessageMap = null; + private final ViewerConfigInputStreamProvider mViewerConfigInputStreamProvider; + private Map<Long, String> mLogMessageMap = null; - /** Returns message format string for its hash or null if unavailable. */ - public synchronized String getViewerString(int messageHash) { - if (mLogMessageMap != null) { - return mLogMessageMap.get(messageHash); - } else { - return null; - } + public ProtoLogViewerConfigReader( + ViewerConfigInputStreamProvider viewerConfigInputStreamProvider) { + this.mViewerConfigInputStreamProvider = viewerConfigInputStreamProvider; } /** - * Reads the specified viewer configuration file. Does nothing if the config is already loaded. + * Returns message format string for its hash or null if unavailable + * or the viewer config is not loaded into memory. */ - public synchronized void loadViewerConfig(PrintWriter pw, String viewerConfigFilename) { - try { - loadViewerConfig(new GZIPInputStream(new FileInputStream(viewerConfigFilename))); - logAndPrintln(pw, "Loaded " + mLogMessageMap.size() - + " log definitions from " + viewerConfigFilename); - } catch (FileNotFoundException e) { - logAndPrintln(pw, "Unable to load log definitions: File " - + viewerConfigFilename + " not found." + e); - } catch (IOException e) { - logAndPrintln(pw, "Unable to load log definitions: IOException while reading " - + viewerConfigFilename + ". " + e); - } catch (JSONException e) { - logAndPrintln(pw, "Unable to load log definitions: JSON parsing exception while reading " - + viewerConfigFilename + ". " + e); + public synchronized String getViewerString(long messageHash) { + if (mLogMessageMap != null) { + return mLogMessageMap.get(messageHash); + } else { + return null; } } /** - * Reads the specified viewer configuration input stream. - * Does nothing if the config is already loaded. + * Loads the viewer config into memory. No-op if already loaded in memory. */ - public synchronized void loadViewerConfig(InputStream viewerConfigInputStream) - throws IOException, JSONException { + public synchronized void loadViewerConfig(ILogger logger) { if (mLogMessageMap != null) { return; } - InputStreamReader config = new InputStreamReader(viewerConfigInputStream); - BufferedReader reader = new BufferedReader(config); - StringBuilder builder = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - builder.append(line).append('\n'); - } - reader.close(); - JSONObject json = new JSONObject(builder.toString()); - JSONObject messages = json.getJSONObject("messages"); - - mLogMessageMap = new TreeMap<>(); - Iterator it = messages.keys(); - while (it.hasNext()) { - String key = (String) it.next(); - try { - int hash = Integer.parseInt(key); - JSONObject val = messages.getJSONObject(key); - String msg = val.getString("message"); - mLogMessageMap.put(hash, msg); - } catch (NumberFormatException expected) { - // Not a messageHash - skip it - } + + try { + doLoadViewerConfig(); + logger.log("Loaded " + mLogMessageMap.size() + " log definitions"); + } catch (IOException e) { + logger.log("Unable to load log definitions: " + + "IOException while processing viewer config" + e); } } /** - * Returns the number of loaded log definitions kept in memory. + * Unload the viewer config from memory. */ - public synchronized int knownViewerStringsNumber() { - if (mLogMessageMap != null) { - return mLogMessageMap.size(); - } - return 0; + public synchronized void unloadViewerConfig() { + mLogMessageMap = null; } - static void logAndPrintln(@Nullable PrintWriter pw, String msg) { - Slog.i(TAG, msg); - if (pw != null) { - pw.println(msg); - pw.flush(); + private void doLoadViewerConfig() throws IOException { + final ProtoInputStream pis = mViewerConfigInputStreamProvider.getInputStream(); + + while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + if (pis.getFieldNumber() == (int) MESSAGES) { + final long inMessageToken = pis.start(MESSAGES); + + long messageId = 0; + String message = null; + while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + switch (pis.getFieldNumber()) { + case (int) MESSAGE_ID: + messageId = pis.readLong(MESSAGE_ID); + break; + case (int) MESSAGE: + message = pis.readString(MESSAGE); + break; + } + } + + if (messageId == 0) { + throw new IOException("Failed to get message id"); + } + + if (message == null) { + throw new IOException("Failed to get message string"); + } + + mLogMessageMap.put(messageId, message); + + pis.end(inMessageToken); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUiModule.kt b/core/java/com/android/internal/protolog/ViewerConfigInputStreamProvider.java index b7285da49bb7..334f5488425a 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUiModule.kt +++ b/core/java/com/android/internal/protolog/ViewerConfigInputStreamProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,19 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.globalactions -import android.content.Context -import com.android.systemui.statusbar.BlurUtils -import dagger.Module -import dagger.Provides +package com.android.internal.protolog; -/** Provides the UI shown during system shutdown. */ -@Module -class ShutdownUiModule { - /** Shutdown UI provider. */ - @Provides - fun provideShutdownUi(context: Context?, blurUtils: BlurUtils?): ShutdownUi { - return ShutdownUi(context, blurUtils) - } +import android.util.proto.ProtoInputStream; + +public interface ViewerConfigInputStreamProvider { + /** + * @return a ProtoInputStream. + */ + ProtoInputStream getInputStream(); } diff --git a/core/java/com/android/internal/protolog/common/ILogger.java b/core/java/com/android/internal/protolog/common/ILogger.java new file mode 100644 index 000000000000..cc6fa5e73969 --- /dev/null +++ b/core/java/com/android/internal/protolog/common/ILogger.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.protolog.common; + +public interface ILogger { + /** + * Log a message. + * @param message The log message. + */ + void log(String message); +} diff --git a/core/java/com/android/internal/protolog/common/IProtoLog.java b/core/java/com/android/internal/protolog/common/IProtoLog.java new file mode 100644 index 000000000000..c06d14b2075e --- /dev/null +++ b/core/java/com/android/internal/protolog/common/IProtoLog.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2023 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.internal.protolog.common; + +/** + * Interface for ProtoLog implementations. + */ +public interface IProtoLog { + + /** + * Log a ProtoLog message + * @param logLevel Log level of the proto message. + * @param group The group this message belongs to. + * @param messageHash The hash of the message. + * @param paramsMask The parameters mask of the message. + * @param messageString The message string. + * @param args The arguments of the message. + */ + void log(LogLevel logLevel, IProtoLogGroup group, long messageHash, int paramsMask, + String messageString, Object[] args); + + /** + * Check if ProtoLog is tracing. + * @return true iff a ProtoLog tracing session is active. + */ + boolean isProtoEnabled(); + + /** + * Start logging log groups to logcat + * @param groups Groups to start text logging for + * @return status code + */ + int startLoggingToLogcat(String[] groups, ILogger logger); + + /** + * Stop logging log groups to logcat + * @param groups Groups to start text logging for + * @return status code + */ + int stopLoggingToLogcat(String[] groups, ILogger logger); +} diff --git a/core/java/com/android/internal/protolog/common/IProtoLogGroup.java b/core/java/com/android/internal/protolog/common/IProtoLogGroup.java index e3db46832a6f..4e9686f99f4b 100644 --- a/core/java/com/android/internal/protolog/common/IProtoLogGroup.java +++ b/core/java/com/android/internal/protolog/common/IProtoLogGroup.java @@ -26,6 +26,7 @@ public interface IProtoLogGroup { boolean isEnabled(); /** + * @deprecated TODO(b/324128613) remove once we migrate fully to Perfetto * is binary logging enabled for the group. */ boolean isLogToProto(); diff --git a/core/java/com/android/internal/protolog/common/ProtoLog.java b/core/java/com/android/internal/protolog/common/ProtoLog.java index 8870096f3db7..18e3f66c4795 100644 --- a/core/java/com/android/internal/protolog/common/ProtoLog.java +++ b/core/java/com/android/internal/protolog/common/ProtoLog.java @@ -16,8 +16,6 @@ package com.android.internal.protolog.common; -import android.util.Log; - /** * ProtoLog API - exposes static logging methods. Usage of this API is similar * to {@code android.utils.Log} class. Instead of plain text log messages each call consists of @@ -55,9 +53,6 @@ public class ProtoLog { throw new UnsupportedOperationException( "ProtoLog calls MUST be processed with ProtoLogTool"); } - if (group.isLogToLogcat()) { - Log.d(group.getTag(), String.format(messageString, args)); - } } /** @@ -73,9 +68,6 @@ public class ProtoLog { throw new UnsupportedOperationException( "ProtoLog calls MUST be processed with ProtoLogTool"); } - if (group.isLogToLogcat()) { - Log.v(group.getTag(), String.format(messageString, args)); - } } /** @@ -91,9 +83,6 @@ public class ProtoLog { throw new UnsupportedOperationException( "ProtoLog calls MUST be processed with ProtoLogTool"); } - if (group.isLogToLogcat()) { - Log.i(group.getTag(), String.format(messageString, args)); - } } /** @@ -109,9 +98,6 @@ public class ProtoLog { throw new UnsupportedOperationException( "ProtoLog calls MUST be processed with ProtoLogTool"); } - if (group.isLogToLogcat()) { - Log.w(group.getTag(), String.format(messageString, args)); - } } /** @@ -127,9 +113,6 @@ public class ProtoLog { throw new UnsupportedOperationException( "ProtoLog calls MUST be processed with ProtoLogTool"); } - if (group.isLogToLogcat()) { - Log.e(group.getTag(), String.format(messageString, args)); - } } /** @@ -145,8 +128,30 @@ public class ProtoLog { throw new UnsupportedOperationException( "ProtoLog calls MUST be processed with ProtoLogTool"); } - if (group.isLogToLogcat()) { - Log.wtf(group.getTag(), String.format(messageString, args)); + } + + /** + * Check if ProtoLog isEnabled for a target group. + * @param group Group to check enable status of. + * @return true iff this is being logged. + */ + public static boolean isEnabled(IProtoLogGroup group) { + if (REQUIRE_PROTOLOGTOOL) { + throw new UnsupportedOperationException( + "ProtoLog calls MUST be processed with ProtoLogTool"); + } + return false; + } + + /** + * Get the single ProtoLog instance. + * @return A singleton instance of ProtoLog. + */ + public static IProtoLog getSingleInstance() { + if (REQUIRE_PROTOLOGTOOL) { + throw new UnsupportedOperationException( + "ProtoLog calls MUST be processed with ProtoLogTool"); } + return null; } } diff --git a/core/java/com/android/internal/protolog/common/ProtoLogToolInjected.java b/core/java/com/android/internal/protolog/common/ProtoLogToolInjected.java new file mode 100644 index 000000000000..ffd0d7623852 --- /dev/null +++ b/core/java/com/android/internal/protolog/common/ProtoLogToolInjected.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.android.internal.protolog.common; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +@Target({ElementType.FIELD, ElementType.PARAMETER}) +public @interface ProtoLogToolInjected { + enum Value { VIEWER_CONFIG_PATH, LEGACY_OUTPUT_FILE_PATH, LEGACY_VIEWER_CONFIG_PATH } + + Value value(); +} diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index d463b62e62a3..6ffc63869f26 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -360,8 +360,12 @@ oneway interface IStatusBar /** Shows rear display educational dialog */ void showRearDisplayDialog(int currentBaseState); - /** Called when requested to go to fullscreen from the active split app. */ - void goToFullscreenFromSplit(); + /** + * Called when requested to go to fullscreen from the focused app. + * + * @param displayId the id of the current display. + */ + void moveFocusedTaskToFullscreen(int displayId); /** * Enters stage split from a current running app. diff --git a/core/java/com/android/internal/widget/ConversationAvatarData.java b/core/java/com/android/internal/widget/ConversationAvatarData.java new file mode 100644 index 000000000000..e04772f72516 --- /dev/null +++ b/core/java/com/android/internal/widget/ConversationAvatarData.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import android.graphics.drawable.Drawable; + +/** + * @hide + */ +interface ConversationAvatarData { + final class OneToOneConversationAvatarData implements ConversationAvatarData { + final Drawable mDrawable; + + OneToOneConversationAvatarData(Drawable drawable) { + mDrawable = drawable; + } + } + + final class GroupConversationAvatarData implements ConversationAvatarData { + final Drawable mLastIcon; + final Drawable mSecondLastIcon; + + GroupConversationAvatarData(Drawable lastIcon, Drawable secondLastIcon) { + mLastIcon = lastIcon; + mSecondLastIcon = secondLastIcon; + } + } +} diff --git a/core/java/com/android/internal/widget/ConversationHeaderData.java b/core/java/com/android/internal/widget/ConversationHeaderData.java new file mode 100644 index 000000000000..0953b3912a91 --- /dev/null +++ b/core/java/com/android/internal/widget/ConversationHeaderData.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +import android.annotation.Nullable; + +/** + * @hide + */ +final class ConversationHeaderData { + private final CharSequence mConversationText; + + private final ConversationAvatarData mConversationAvatarData; + + ConversationHeaderData(CharSequence conversationText, + ConversationAvatarData conversationAvatarData) { + mConversationText = conversationText; + mConversationAvatarData = conversationAvatarData; + } + + @Nullable + CharSequence getConversationText() { + return mConversationText; + } + + @Nullable + ConversationAvatarData getConversationAvatar() { + return mConversationAvatarData; + } +} diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java index 889434f40472..06835f00755f 100644 --- a/core/java/com/android/internal/widget/ConversationLayout.java +++ b/core/java/com/android/internal/widget/ConversationLayout.java @@ -34,8 +34,10 @@ import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Rect; import android.graphics.Typeface; +import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.Icon; +import android.net.Uri; import android.os.Bundle; import android.os.Parcelable; import android.text.Spannable; @@ -59,8 +61,11 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RemoteViews; import android.widget.TextView; +import android.widget.flags.Flags; import com.android.internal.R; +import com.android.internal.widget.ConversationAvatarData.GroupConversationAvatarData; +import com.android.internal.widget.ConversationAvatarData.OneToOneConversationAvatarData; import java.util.ArrayList; import java.util.List; @@ -403,11 +408,14 @@ public class ConversationLayout extends FrameLayout */ @RemotableViewMethod(asyncImpl = "setDataAsync") public void setData(Bundle extras) { - bind(parseMessagingData(extras, /* usePrecomputedText= */ false)); + bind(parseMessagingData(extras, + /* usePrecomputedText= */ false, + /*includeConversationIcon= */false)); } @NonNull - private MessagingData parseMessagingData(Bundle extras, boolean usePrecomputedText) { + private MessagingData parseMessagingData(Bundle extras, boolean usePrecomputedText, + boolean includeConversationIcon) { Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES); List<Notification.MessagingStyle.Message> newMessages = Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages); @@ -438,8 +446,20 @@ public class ConversationLayout extends FrameLayout // Lets first find the groups (populate `groups` and `senders`) findGroups(newHistoricMessagingMessages, newMessagingMessages, user, groups, senders); + // load conversation header data, avatar and title. + final ConversationHeaderData conversationHeaderData; + if (includeConversationIcon && Flags.conversationStyleSetAvatarAsync()) { + conversationHeaderData = loadConversationHeaderData(mIsOneToOne, + mConversationTitle, + mShortcutIcon, + mLargeIcon, newMessagingMessages, user, groups, mLayoutColor); + } else { + conversationHeaderData = null; + } + return new MessagingData(user, showSpinner, unreadCount, - newHistoricMessagingMessages, newMessagingMessages, groups, senders); + newHistoricMessagingMessages, newMessagingMessages, groups, senders, + conversationHeaderData); } /** @@ -457,7 +477,9 @@ public class ConversationLayout extends FrameLayout } final MessagingData messagingData = - parseMessagingData(extras, /* usePrecomputedText= */ true); + parseMessagingData(extras, + /* usePrecomputedText= */ true, + /*includeConversationIcon=*/true); return () -> { finalizeInflate(messagingData.getHistoricMessagingMessages()); @@ -536,11 +558,10 @@ public class ConversationLayout extends FrameLayout mMessages = messagingData.getNewMessagingMessages(); mHistoricMessages = messagingData.getHistoricMessagingMessages(); - updateHistoricMessageVisibility(); updateTitleAndNamesDisplay(); - updateConversationLayout(); + updateConversationLayout(messagingData); // Recycle everything at the end of the update, now that we know it's no longer needed. for (MessagingLinearLayout.MessagingChild child : mToRecycle) { @@ -552,7 +573,31 @@ public class ConversationLayout extends FrameLayout /** * Update the layout according to the data provided (i.e mIsOneToOne, expanded etc); */ - private void updateConversationLayout() { + private void updateConversationLayout(MessagingData messagingData) { + if (!Flags.conversationStyleSetAvatarAsync()) { + computeAndSetConversationAvatarAndName(); + } else { + ConversationHeaderData conversationHeaderData = + messagingData.getConversationHeaderData(); + if (conversationHeaderData == null) { + conversationHeaderData = loadConversationHeaderData(mIsOneToOne, + mConversationTitle, mShortcutIcon, mLargeIcon, mMessages, mUser, + messagingData.getGroups(), + mLayoutColor); + } + setConversationAvatarAndNameFromData(conversationHeaderData); + } + + updateAppName(); + updateIconPositionAndSize(); + updateImageMessages(); + updatePaddingsBasedOnContentAvailability(); + updateActionListPadding(); + updateAppNameDividerVisibility(); + } + + @Deprecated + private void computeAndSetConversationAvatarAndName() { // Set avatar and name CharSequence conversationText = mConversationTitle; mConversationIcon = mShortcutIcon; @@ -603,12 +648,43 @@ public class ConversationLayout extends FrameLayout // Update if the groups can hide the sender if they are first (applies to 1:1 conversations) // This needs to happen after all of the above o update all of the groups mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, conversationText); - updateAppName(); - updateIconPositionAndSize(); - updateImageMessages(); - updatePaddingsBasedOnContentAvailability(); - updateActionListPadding(); - updateAppNameDividerVisibility(); + } + + private void setConversationAvatarAndNameFromData( + ConversationHeaderData conversationHeaderData) { + final OneToOneConversationAvatarData oneToOneConversationDrawable; + final GroupConversationAvatarData groupConversationAvatarData; + final ConversationAvatarData conversationAvatar = + conversationHeaderData.getConversationAvatar(); + if (conversationAvatar instanceof OneToOneConversationAvatarData) { + oneToOneConversationDrawable = + ((OneToOneConversationAvatarData) conversationAvatar); + groupConversationAvatarData = null; + } else { + oneToOneConversationDrawable = null; + groupConversationAvatarData = ((GroupConversationAvatarData) conversationAvatar); + } + + if (oneToOneConversationDrawable != null) { + mConversationIconView.setVisibility(VISIBLE); + mConversationFacePile.setVisibility(GONE); + mConversationIconView.setImageDrawable(oneToOneConversationDrawable.mDrawable); + } else { + mConversationIconView.setVisibility(GONE); + // This will also inflate it! + mConversationFacePile.setVisibility(VISIBLE); + // rebind the value to the inflated view instead of the stub + mConversationFacePile = findViewById(R.id.conversation_face_pile); + bindFacePile(groupConversationAvatarData); + } + CharSequence conversationText = conversationHeaderData.getConversationText(); + if (TextUtils.isEmpty(conversationText)) { + conversationText = mIsOneToOne ? mFallbackChatName : mFallbackGroupChatName; + } + mConversationText.setText(conversationText); + // Update if the groups can hide the sender if they are first (applies to 1:1 conversations) + // This needs to happen after all of the above o update all of the groups + mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, conversationText); } private void updateActionListPadding() { @@ -675,7 +751,12 @@ public class ConversationLayout extends FrameLayout topView.setImageIcon(secondLastIcon); } + @Deprecated private void bindFacePile() { + bindFacePile(null); + } + + private void bindFacePile(@Nullable GroupConversationAvatarData groupConversationAvatarData) { ImageView bottomBackground = mConversationFacePile.findViewById( R.id.conversation_face_pile_bottom_background); ImageView bottomView = mConversationFacePile.findViewById( @@ -683,7 +764,13 @@ public class ConversationLayout extends FrameLayout ImageView topView = mConversationFacePile.findViewById( R.id.conversation_face_pile_top); - bindFacePile(bottomBackground, bottomView, topView); + if (groupConversationAvatarData == null) { + bindFacePile(bottomBackground, bottomView, topView); + } else { + bindFacePileWithDrawable(bottomBackground, bottomView, topView, + groupConversationAvatarData); + + } int conversationAvatarSize; int facepileAvatarSize; @@ -718,6 +805,13 @@ public class ConversationLayout extends FrameLayout bottomBackground.setLayoutParams(layoutParams); } + private void bindFacePileWithDrawable(ImageView bottomBackground, ImageView bottomView, + ImageView topView, GroupConversationAvatarData groupConversationAvatarData) { + applyNotificationBackgroundColor(bottomBackground); + bottomView.setImageDrawable(groupConversationAvatarData.mLastIcon); + topView.setImageDrawable(groupConversationAvatarData.mSecondLastIcon); + } + private void updateAppName() { mAppName.setVisibility(mIsCollapsed ? GONE : VISIBLE); } @@ -789,22 +883,62 @@ public class ConversationLayout extends FrameLayout mMessagingLinearLayout.getPaddingBottom()); } + /** + * async version of {@link ConversationLayout#setLargeIcon} + */ @RemotableViewMethod + public Runnable setLargeIconAsync(Icon largeIcon) { + if (!Flags.conversationStyleSetAvatarAsync()) { + return () -> setLargeIcon(largeIcon); + } + + mLargeIcon = largeIcon; + return NotificationRunnables.NOOP; + } + + @RemotableViewMethod(asyncImpl = "setLargeIconAsync") public void setLargeIcon(Icon largeIcon) { mLargeIcon = largeIcon; } + /** + * async version of {@link ConversationLayout#setShortcutIcon} + */ @RemotableViewMethod + public Runnable setShortcutIconAsync(Icon shortcutIcon) { + if (!Flags.conversationStyleSetAvatarAsync()) { + return () -> setShortcutIcon(shortcutIcon); + } + + mShortcutIcon = shortcutIcon; + return NotificationRunnables.NOOP; + } + + @RemotableViewMethod(asyncImpl = "setShortcutIconAsync") public void setShortcutIcon(Icon shortcutIcon) { mShortcutIcon = shortcutIcon; } /** + * async version of {@link ConversationLayout#setConversationTitle} + */ + @RemotableViewMethod + public Runnable setConversationTitleAsync(CharSequence conversationTitle) { + if (!Flags.conversationStyleSetAvatarAsync()) { + return () -> setConversationTitle(conversationTitle); + } + + // Remove formatting from the title. + mConversationTitle = conversationTitle != null ? conversationTitle.toString() : null; + return NotificationRunnables.NOOP; + } + + /** * Sets the conversation title of this conversation. * * @param conversationTitle the conversation title */ - @RemotableViewMethod + @RemotableViewMethod(asyncImpl = "setConversationTitleAsync") public void setConversationTitle(CharSequence conversationTitle) { // Remove formatting from the title. mConversationTitle = conversationTitle != null ? conversationTitle.toString() : null; @@ -888,12 +1022,37 @@ public class ConversationLayout extends FrameLayout } } + /** + * async version of {@link ConversationLayout#setLayoutColor} + */ @RemotableViewMethod + public Runnable setLayoutColorAsync(int color) { + if (!Flags.conversationStyleSetAvatarAsync()) { + return () -> setLayoutColor(color); + } + + mLayoutColor = color; + return NotificationRunnables.NOOP; + } + + @RemotableViewMethod(asyncImpl = "setLayoutColorAsync") public void setLayoutColor(int color) { mLayoutColor = color; } + /** + * async version of {@link ConversationLayout#setIsOneToOne} + */ @RemotableViewMethod + public Runnable setIsOneToOneAsync(boolean oneToOne) { + if (!Flags.conversationStyleSetAvatarAsync()) { + return () -> setIsOneToOne(oneToOne); + } + mIsOneToOne = oneToOne; + return NotificationRunnables.NOOP; + } + + @RemotableViewMethod(asyncImpl = "setIsOneToOneAsync") public void setIsOneToOne(boolean oneToOne) { mIsOneToOne = oneToOne; } @@ -1022,6 +1181,125 @@ public class ConversationLayout extends FrameLayout return person == null ? null : person.getKey() == null ? person.getName() : person.getKey(); } + private ConversationHeaderData loadConversationHeaderData(boolean isOneToOne, + CharSequence conversationTitle, Icon shortcutIcon, Icon largeIcon, + List<MessagingMessage> messages, + Person user, + List<List<MessagingMessage>> groups, int layoutColor) { + Icon conversationIcon = shortcutIcon; + CharSequence conversationText = conversationTitle; + final CharSequence userKey = getKey(user); + if (isOneToOne) { + for (int i = messages.size() - 1; i >= 0; i--) { + final Notification.MessagingStyle.Message message = messages.get(i).getMessage(); + final Person sender = message.getSenderPerson(); + final CharSequence senderKey = getKey(sender); + if ((sender != null && senderKey != userKey) || i == 0) { + if (conversationText == null || conversationText.length() == 0) { + conversationText = sender != null ? sender.getName() : ""; + } + if (conversationIcon == null) { + conversationIcon = sender != null ? sender.getIcon() + : mPeopleHelper.createAvatarSymbol(conversationText, "", + layoutColor); + } + break; + } + } + } + + if (conversationIcon == null) { + conversationIcon = largeIcon; + } + + if (isOneToOne || conversationIcon != null) { + return new ConversationHeaderData( + conversationText, + new OneToOneConversationAvatarData( + resolveAvatarImage(conversationIcon))); + } + + final List<List<Notification.MessagingStyle.Message>> groupMessages = new ArrayList<>(); + for (int i = 0; i < groups.size(); i++) { + final List<Notification.MessagingStyle.Message> groupMessage = new ArrayList<>(); + for (int j = 0; j < groups.get(i).size(); j++) { + groupMessage.add(groups.get(i).get(j).getMessage()); + } + groupMessages.add(groupMessage); + } + + final PeopleHelper.NameToPrefixMap nameToPrefixMap = + mPeopleHelper.mapUniqueNamesToPrefixWithGroupList(groupMessages); + + Icon lastIcon = null; + Icon secondLastIcon = null; + + CharSequence lastKey = null; + + for (int i = groups.size() - 1; i >= 0; i--) { + final Notification.MessagingStyle.Message message = groups.get(i).get(0).getMessage(); + final Person sender = + message.getSenderPerson() != null ? message.getSenderPerson() : user; + final CharSequence senderKey = getKey(sender); + final boolean notUser = senderKey != userKey; + final boolean notIncluded = senderKey != lastKey; + + if ((notUser && notIncluded) || (i == 0 && lastKey == null)) { + if (lastIcon == null) { + if (sender.getIcon() != null) { + lastIcon = sender.getIcon(); + } else { + final CharSequence senderName = + sender.getName() != null ? sender.getName() : ""; + lastIcon = mPeopleHelper.createAvatarSymbol( + senderName, nameToPrefixMap.getPrefix(senderName), + layoutColor); + } + lastKey = senderKey; + } else { + if (sender.getIcon() != null) { + secondLastIcon = sender.getIcon(); + } else { + final CharSequence senderName = + sender.getName() != null ? sender.getName() : ""; + secondLastIcon = mPeopleHelper.createAvatarSymbol( + senderName, nameToPrefixMap.getPrefix(senderName), + layoutColor); + } + break; + } + } + } + + if (lastIcon == null) { + lastIcon = mPeopleHelper.createAvatarSymbol( + "", "", layoutColor); + } + + if (secondLastIcon == null) { + secondLastIcon = mPeopleHelper.createAvatarSymbol( + "", "", layoutColor); + } + + return new ConversationHeaderData( + conversationText, + new GroupConversationAvatarData(resolveAvatarImage(lastIcon), + resolveAvatarImage(secondLastIcon))); + } + + /** + * {@link ImageResolver#loadImage(Uri)} accepts Uri to load images. However Conversation Avatars + * are received as Icon. So, we can't make use of ImageResolver. + */ + @Nullable + private Drawable resolveAvatarImage(Icon conversationIcon) { + try { + return LocalImageResolver.resolveImage(conversationIcon, getContext()); + } catch (Exception ex) { + return null; + } + } + /** * Creates new messages, reusing existing ones if they are available. * diff --git a/core/java/com/android/internal/widget/MessagingData.java b/core/java/com/android/internal/widget/MessagingData.java index 42de60e08e18..fb1f28fb8ef3 100644 --- a/core/java/com/android/internal/widget/MessagingData.java +++ b/core/java/com/android/internal/widget/MessagingData.java @@ -16,6 +16,7 @@ package com.android.internal.widget; +import android.annotation.Nullable; import android.app.Person; import java.util.List; @@ -32,6 +33,8 @@ final class MessagingData { private final List<Person> mSenders; private final int mUnreadCount; + private ConversationHeaderData mConversationHeaderData; + MessagingData(Person user, boolean showSpinner, List<MessagingMessage> historicMessagingMessages, List<MessagingMessage> newMessagingMessages, List<List<MessagingMessage>> groups, @@ -39,7 +42,7 @@ final class MessagingData { this(user, showSpinner, /* unreadCount= */0, historicMessagingMessages, newMessagingMessages, groups, - senders); + senders, null); } MessagingData(Person user, boolean showSpinner, @@ -47,7 +50,8 @@ final class MessagingData { List<MessagingMessage> historicMessagingMessages, List<MessagingMessage> newMessagingMessages, List<List<MessagingMessage>> groups, - List<Person> senders) { + List<Person> senders, + @Nullable ConversationHeaderData conversationHeaderData) { mUser = user; mShowSpinner = showSpinner; mUnreadCount = unreadCount; @@ -55,6 +59,7 @@ final class MessagingData { mNewMessagingMessages = newMessagingMessages; mGroups = groups; mSenders = senders; + mConversationHeaderData = conversationHeaderData; } public Person getUser() { @@ -84,4 +89,9 @@ final class MessagingData { public List<List<MessagingMessage>> getGroups() { return mGroups; } + + @Nullable + public ConversationHeaderData getConversationHeaderData() { + return mConversationHeaderData; + } } diff --git a/core/java/com/android/internal/widget/NotificationRunnables.java b/core/java/com/android/internal/widget/NotificationRunnables.java new file mode 100644 index 000000000000..cb7ae617fbea --- /dev/null +++ b/core/java/com/android/internal/widget/NotificationRunnables.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.widget; + +public final class NotificationRunnables { + public static final Runnable NOOP = () -> { + }; +} diff --git a/core/jni/LayoutlibLoader.cpp b/core/jni/LayoutlibLoader.cpp index 01e9f437a79f..06d5eb305ff0 100644 --- a/core/jni/LayoutlibLoader.cpp +++ b/core/jni/LayoutlibLoader.cpp @@ -362,6 +362,22 @@ static void init_keyboard(JNIEnv* env, const vector<string>& keyboardPaths) { using namespace android; +// Called right before aborting by LOG_ALWAYS_FATAL. Print the pending exception. +void abort_handler(const char* abort_message) { + ALOGE("Abort to abort the process..."); + + JNIEnv* env = NULL; + if (javaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + ALOGE("vm->GetEnv() failed"); + return; + } + if (env->ExceptionOccurred() != NULL) { + ALOGE("Pending exception:"); + env->ExceptionDescribe(); + } + ALOGE("Aborting because: %s", abort_message); +} + JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) { javaVM = vm; JNIEnv* env = nullptr; @@ -369,6 +385,8 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) { return JNI_ERR; } + __android_log_set_aborter(abort_handler); + init_android_graphics(); // Configuration is stored as java System properties. diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 070d07c22fbc..52237989f059 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -18,6 +18,8 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "AudioSystem-JNI" +#include <android/binder_ibinder_jni.h> +#include <android/binder_libbinder.h> #include <android/media/AudioVibratorInfo.h> #include <android/media/INativeSpatializerCallback.h> #include <android/media/ISpatializer.h> @@ -25,6 +27,7 @@ #include <android_media_audiopolicy.h> #include <android_os_Parcel.h> #include <audiomanager/AudioManager.h> +#include <binder/IBinder.h> #include <jni.h> #include <media/AidlConversion.h> #include <media/AudioContainers.h> @@ -150,13 +153,14 @@ static struct { static jclass gAudioMixClass; static jmethodID gAudioMixCstor; static struct { - jfieldID mRule; - jfieldID mFormat; - jfieldID mRouteFlags; - jfieldID mDeviceType; - jfieldID mDeviceAddress; - jfieldID mMixType; - jfieldID mCallbackFlags; + jfieldID mRule; + jfieldID mFormat; + jfieldID mRouteFlags; + jfieldID mDeviceType; + jfieldID mDeviceAddress; + jfieldID mMixType; + jfieldID mCallbackFlags; + jfieldID mToken; } gAudioMixFields; static jclass gAudioFormatClass; @@ -2300,11 +2304,15 @@ static jint convertAudioMixFromNative(JNIEnv *env, jobject *jAudioMix, const Aud if (status != AUDIO_JAVA_SUCCESS) { return status; } + std::unique_ptr<AIBinder, decltype(&AIBinder_decStrong)> aiBinder(AIBinder_fromPlatformBinder( + nAudioMix.mToken), + &AIBinder_decStrong); + jobject jBinderToken = AIBinder_toJavaBinder(env, aiBinder.get()); jstring deviceAddress = env->NewStringUTF(nAudioMix.mDeviceAddress.c_str()); *jAudioMix = env->NewObject(gAudioMixClass, gAudioMixCstor, jAudioMixingRule, jAudioFormat, nAudioMix.mRouteFlags, nAudioMix.mCbFlags, nAudioMix.mDeviceType, - deviceAddress); + deviceAddress, jBinderToken); return AUDIO_JAVA_SUCCESS; } @@ -2333,6 +2341,12 @@ static jint convertAudioMixToNative(JNIEnv *env, AudioMix *nAudioMix, const jobj nAudioMix->mVoiceCommunicationCaptureAllowed = env->GetBooleanField(jRule, gAudioMixingRuleFields.mVoiceCommunicationCaptureAllowed); + jobject jToken = env->GetObjectField(jAudioMix, gAudioMixFields.mToken); + + std::unique_ptr<AIBinder, decltype(&AIBinder_decStrong)> + aiBinder(AIBinder_fromJavaBinder(env, jToken), &AIBinder_decStrong); + nAudioMix->mToken = AIBinder_toPlatformBinder(aiBinder.get()); + jint status = convertAudioMixingRuleToNative(env, jRule, &(nAudioMix->mCriteria)); env->DeleteLocalRef(jRule); @@ -3659,9 +3673,10 @@ int register_android_media_AudioSystem(JNIEnv *env) jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix"); gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass); if (audio_flags::audio_mix_test_api()) { - gAudioMixCstor = GetMethodIDOrDie(env, audioMixClass, "<init>", - "(Landroid/media/audiopolicy/AudioMixingRule;Landroid/" - "media/AudioFormat;IIILjava/lang/String;)V"); + gAudioMixCstor = + GetMethodIDOrDie(env, audioMixClass, "<init>", + "(Landroid/media/audiopolicy/AudioMixingRule;Landroid/" + "media/AudioFormat;IIILjava/lang/String;Landroid/os/IBinder;)V"); } gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule", "Landroid/media/audiopolicy/AudioMixingRule;"); @@ -3673,6 +3688,7 @@ int register_android_media_AudioSystem(JNIEnv *env) "Ljava/lang/String;"); gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I"); gAudioMixFields.mCallbackFlags = GetFieldIDOrDie(env, audioMixClass, "mCallbackFlags", "I"); + gAudioMixFields.mToken = GetFieldIDOrDie(env, audioMixClass, "mToken", "Landroid/os/IBinder;"); jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat"); gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass); diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 285dee364bb0..b39d5cf3842b 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -85,9 +85,24 @@ static void android_view_MotionEvent_setNativePtr(JNIEnv* env, ScopedLocalRef<jo ScopedLocalRef<jobject> android_view_MotionEvent_obtainAsCopy(JNIEnv* env, const MotionEvent& event) { - std::unique_ptr<MotionEvent> destEvent = std::make_unique<MotionEvent>(); + ScopedLocalRef<jobject> eventObj(env, + env->CallStaticObjectMethod(gMotionEventClassInfo.clazz, + gMotionEventClassInfo.obtain)); + if (env->ExceptionCheck() || !eventObj.get()) { + ALOGE("An exception occurred while obtaining a motion event."); + LOGE_EX(env); + env->ExceptionClear(); + return ScopedLocalRef<jobject>(env); + } + + MotionEvent* destEvent = android_view_MotionEvent_getNativePtr(env, eventObj.get()); + if (!destEvent) { + destEvent = new MotionEvent(); + android_view_MotionEvent_setNativePtr(env, eventObj, destEvent); + } + destEvent->copyFrom(&event, true); - return android_view_MotionEvent_obtainFromNative(env, std::move(destEvent)); + return eventObj; } ScopedLocalRef<jobject> android_view_MotionEvent_obtainFromNative( diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 0938ce17a4c0..3ed9f49ede26 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -1965,7 +1965,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, // If this zygote isn't root, it won't be able to create a process group, // since the directory is owned by root. - if (!is_system_server && getuid() == 0) { + if (getuid() == 0) { const int rc = createProcessGroup(uid, getpid()); if (rc != 0) { fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing " diff --git a/core/proto/android/internal/protolog.proto b/core/proto/android/internal/protolog.proto index fee7a878f860..9e205e284c53 100644 --- a/core/proto/android/internal/protolog.proto +++ b/core/proto/android/internal/protolog.proto @@ -27,7 +27,7 @@ message ProtoLogMessage { option (.android.msg_privacy).dest = DEST_LOCAL; /* log statement identifier, created from message string and log level. */ - optional sfixed32 message_hash = 1; + optional sfixed32 message_hash_legacy = 1 [deprecated = true]; /* log time, relative to the elapsed system time clock. */ optional fixed64 elapsed_realtime_nanos = 2; /* string parameters passed to the log call. */ @@ -38,6 +38,9 @@ message ProtoLogMessage { repeated double double_params = 5 [packed=true]; /* boolean parameters passed to the log call. */ repeated bool boolean_params = 6 [packed=true]; + + /* log statement identifier, created from message string and log level. */ + optional sfixed64 message_hash = 7; } /* represents a log file containing ProtoLog log entries. diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index 4fc9b40465ee..763d9ce1a053 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -101,6 +101,7 @@ message SecureSettingsProto { optional SettingProto accessibility_magnification_two_finger_triple_tap_enabled = 53 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto qs_targets = 54 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto accessibility_pinch_to_zoom_anywhere_enabled = 55 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto accessibility_single_finger_panning_enabled = 56 [ (android.privacy).dest = DEST_AUTOMATIC ]; } optional Accessibility accessibility = 2; diff --git a/core/res/Android.bp b/core/res/Android.bp index 277824cbb4c8..e2e419fcf5b7 100644 --- a/core/res/Android.bp +++ b/core/res/Android.bp @@ -159,7 +159,7 @@ android_app { "android.content.pm.flags-aconfig", "android.provider.flags-aconfig", "camera_platform_flags", - "com.android.net.flags-aconfig", + "android.net.platform.flags-aconfig", "com.android.window.flags.window-aconfig", ], } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 8720f947bb8d..487b5be9ef5c 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2281,7 +2281,7 @@ <!-- @SystemApi @hide Allows changing Thread network state and access to Thread network credentials such as Network Key and PSKc. <p>Not for use by third-party applications. - @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") --> + @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") --> <permission android:name="android.permission.THREAD_NETWORK_PRIVILEGED" android:protectionLevel="signature|privileged" /> @@ -2331,12 +2331,12 @@ <!-- Allows system apps to call methods to register itself as a mDNS offload engine. <p>Not for use by third-party or privileged applications. @SystemApi - @FlaggedApi("com.android.net.flags.register_nsd_offload_engine") + @FlaggedApi("android.net.platform.flags.register_nsd_offload_engine") @hide This should only be used by system apps. --> <permission android:name="android.permission.REGISTER_NSD_OFFLOAD_ENGINE" android:protectionLevel="signature" - android:featureFlag="com.android.net.flags.register_nsd_offload_engine" /> + android:featureFlag="android.net.platform.flags.register_nsd_offload_engine" /> <!-- ======================================= --> <!-- Permissions for short range, peripheral networks --> @@ -3629,7 +3629,7 @@ <!-- Allows an application to set policy related to <a href="https://www.threadgroup.org">Thread</a> network. - @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") + @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") --> <permission android:name="android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK" android:protectionLevel="internal|role" /> @@ -7986,7 +7986,7 @@ @hide --> <permission android:name="android.permission.GET_APP_METADATA" - android:protectionLevel="signature|installer" /> + android:protectionLevel="signature|installer|verifier" /> <!-- @hide @SystemApi Allows an application to stage HealthConnect's remote data so that HealthConnect can later integrate it. --> diff --git a/core/res/res/drawable/pointer_wait_vector.xml b/core/res/res/drawable/pointer_wait_vector.xml new file mode 100644 index 000000000000..4de0690bc26b --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="utf-8"?> +<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> + <item android:drawable="@drawable/pointer_wait_vector_0" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_1" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_2" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_3" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_4" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_5" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_6" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_7" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_8" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_9" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_10" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_11" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_12" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_13" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_14" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_15" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_16" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_17" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_18" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_19" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_20" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_21" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_22" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_23" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_24" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_25" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_26" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_27" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_28" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_29" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_30" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_31" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_32" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_33" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_34" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_35" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_36" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_37" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_38" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_39" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_40" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_41" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_42" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_43" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_44" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_45" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_46" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_47" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_48" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_49" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_50" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_51" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_52" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_53" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_54" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_55" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_56" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_57" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_58" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_59" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_60" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_61" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_62" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_63" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_64" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_65" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_66" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_67" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_68" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_69" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_70" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_71" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_72" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_73" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_74" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_75" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_76" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_77" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_78" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_79" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_80" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_81" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_82" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_83" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_84" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_85" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_86" android:duration="16"/> + <item android:drawable="@drawable/pointer_wait_vector_87" android:duration="16"/> +</animation-list> diff --git a/core/res/res/drawable/pointer_wait_vector_0.xml b/core/res/res/drawable/pointer_wait_vector_0.xml new file mode 100644 index 000000000000..4bfbc9f08b1e --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_0.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.116,18.654a1.78,1.78 0,1 0,0.061 3.561,1.78 1.78,0 0,0 -0.061,-3.561m-7.194,-1.73a1.781,1.781 0,1 0,2.594 2.441,1.781 1.781,0 0,0 -2.594,-2.441" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.294,7.294a1.78,1.78 0,1 0,-2.517 -2.519,1.78 1.78,0 0,0 2.517,2.519" + android:fillColor="#FFF"/> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.225,7.294a1.78,1.78 0,1 0,-2.517 -2.519,1.78 1.78,0 0,0 2.517,2.519" + android:fillColor="#FFF"/> + <path + android:pathData="M20.436,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.747,16.665a1.78,1.78 0,1 0,2.539 2.497,1.78 1.78,0 0,0 -2.539,-2.497" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_1.xml b/core/res/res/drawable/pointer_wait_vector_1.xml new file mode 100644 index 000000000000..bab91e1d9402 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_1.xml @@ -0,0 +1,21 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.174,18.653a1.782,1.782 0,1 0,0.094 3.562,1.782 1.782,0 0,0 -0.094,-3.562m-7.187,-1.637a1.782,1.782 0,1 0,2.627 2.407,1.782 1.782,0 0,0 -2.627,-2.407" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.294,7.294a1.78,1.78 0,1 0,-2.517 -2.519,1.78 1.78,0 0,0 2.517,2.519" + android:fillColor="#FFF"/> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.225,7.294a1.78,1.78 0,1 0,-2.517 -2.519,1.78 1.78,0 0,0 2.517,2.519m1.203,2.888a1.78,1.78 0,1 0,0.016 3.562,1.78 1.78,0 1,0 -0.016,-3.562m-3.641,6.441a1.782,1.782 0,1 0,2.564 2.475,1.782 1.782,0 0,0 -2.564,-2.475" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_10.xml b/core/res/res/drawable/pointer_wait_vector_10.xml new file mode 100644 index 000000000000..ae3e36093aaa --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_10.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.028,20.374m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.952,18.76m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12.066m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.957,6.113m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.779,3.566m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.7,5.78m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.42,11.485m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.462,17.423m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_11.xml b/core/res/res/drawable/pointer_wait_vector_11.xml new file mode 100644 index 000000000000..d2c014d1ee3d --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_11.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.101,20.364m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.101,18.868m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12.074m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.931,6.139m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.706,3.569m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.646,5.731m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.41,11.338m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.509,17.366m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_12.xml b/core/res/res/drawable/pointer_wait_vector_12.xml new file mode 100644 index 000000000000..e9a36c033ca6 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_12.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.247,20.344m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.222,18.953m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.564,12.147m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.88,6.193m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.632,3.571m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.591,5.681m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.404,11.265m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.602,17.252m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_13.xml b/core/res/res/drawable/pointer_wait_vector_13.xml new file mode 100644 index 000000000000..5800f39fa7ef --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_13.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.392,20.321m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.344,19.035m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.565,12.184m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.83,6.246m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.559,3.575m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.535,5.633m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.39,11.118m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.693,17.136m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_14.xml b/core/res/res/drawable/pointer_wait_vector_14.xml new file mode 100644 index 000000000000..3566aaf358e7 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_14.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.537,20.295m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.467,19.115m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.567,12.258m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.755,6.327m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.485,3.579m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.423,5.537m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.386,11.082m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.759,17.048m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_15.xml b/core/res/res/drawable/pointer_wait_vector_15.xml new file mode 100644 index 000000000000..c995faf24f33 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_15.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.682,20.267m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.718,19.269m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.568,12.295m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.73,6.355m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.412,3.584m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.367,5.49m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.369,10.935m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.847,16.929m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_16.xml b/core/res/res/drawable/pointer_wait_vector_16.xml new file mode 100644 index 000000000000..179328205776 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_16.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.826,20.237m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.846,19.343m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.57,12.331m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.706,6.382m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.338,3.589m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.31,5.444m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.354,10.826m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.91,16.839m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_17.xml b/core/res/res/drawable/pointer_wait_vector_17.xml new file mode 100644 index 000000000000..59772f566644 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_17.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.969,20.204m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.974,19.414m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.571,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.681,6.41m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.191,3.602m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.194,5.352m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.333,10.68m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.994,16.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_18.xml b/core/res/res/drawable/pointer_wait_vector_18.xml new file mode 100644 index 000000000000..1bbb242d5663 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_18.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M14.184,20.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.236,19.55m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.575,12.442m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.585,6.521m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.118,3.61m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.136,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.315,10.571m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.075,16.595m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_19.xml b/core/res/res/drawable/pointer_wait_vector_19.xml new file mode 100644 index 000000000000..b8e0dd54708f --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_19.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M14.325,20.11m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.434,19.646m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.581,12.552m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.537,6.577m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.972,3.626m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.959,5.175m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.282,10.39m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.193,16.408m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_2.xml b/core/res/res/drawable/pointer_wait_vector_2.xml new file mode 100644 index 000000000000..5c4606f36569 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_2.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.331,20.43m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.355,18.269m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.035m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.435,11.89m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.094,17.834m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_20.xml b/core/res/res/drawable/pointer_wait_vector_20.xml new file mode 100644 index 000000000000..b3ac2dab2537 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_20.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M14.607,20.024m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.703,19.766m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.592,12.699m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.49,6.634m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.899,3.636m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.899,5.132m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.252,10.246m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.269,16.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_21.xml b/core/res/res/drawable/pointer_wait_vector_21.xml new file mode 100644 index 000000000000..884476e929a6 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_21.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M14.816,19.953m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.908,19.849m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.589,12.662m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.443,6.691m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.753,3.656m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.718,5.006m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.22,10.102m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.414,16.025m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_22.xml b/core/res/res/drawable/pointer_wait_vector_22.xml new file mode 100644 index 000000000000..20660ca89f3a --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_22.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M15.092,19.849m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.184,19.952m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.617,12.955m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.352,6.806m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.608,3.679m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.595,4.925m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.149,9.816m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.483,15.896m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_23.xml b/core/res/res/drawable/pointer_wait_vector_23.xml new file mode 100644 index 000000000000..6b594ee78eae --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_23.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M15.296,19.766m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.533,20.068m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.609,12.882m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.262,6.923m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.463,3.705m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.471,4.845m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.11,9.675m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.614,15.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_24.xml b/core/res/res/drawable/pointer_wait_vector_24.xml new file mode 100644 index 000000000000..a35203e3857b --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_24.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M15.632,19.615m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.816,20.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.626,13.028m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.175,7.041m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.318,3.733m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.346,4.769m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.046,9.463m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.677,15.498m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_25.xml b/core/res/res/drawable/pointer_wait_vector_25.xml new file mode 100644 index 000000000000..df8549af4006 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_25.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M15.896,19.483m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.174,20.236m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.645,13.174m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.089,7.161m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.174,3.763m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.219,4.694m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.977,9.253m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.794,15.228m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_26.xml b/core/res/res/drawable/pointer_wait_vector_26.xml new file mode 100644 index 000000000000..0abb7d41a59a --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_26.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M16.154,19.343m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.535,20.308m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.667,13.32m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.006,7.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.959,3.814m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M15.961,4.551m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.902,9.045m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.902,14.955m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_27.xml b/core/res/res/drawable/pointer_wait_vector_27.xml new file mode 100644 index 000000000000..bde242548af5 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_27.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M16.471,19.155m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.972,20.374m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.691,13.465m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.885,7.467m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.817,3.851m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M15.831,4.483m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.85,8.908m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.023,14.607m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_28.xml b/core/res/res/drawable/pointer_wait_vector_28.xml new file mode 100644 index 000000000000..19cb410b1405 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_28.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M16.778,18.953m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.411,20.416m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.718,13.61m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.807,7.592m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.604,3.911m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M15.566,4.354m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.677,8.502m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.109,14.325m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_29.xml b/core/res/res/drawable/pointer_wait_vector_29.xml new file mode 100644 index 000000000000..5d6776fcdb21 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_29.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M17.136,18.693m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.926,20.436m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.748,13.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.731,7.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.463,3.954m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M15.365,4.263m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.55,8.236m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.203,13.969m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_3.xml b/core/res/res/drawable/pointer_wait_vector_3.xml new file mode 100644 index 000000000000..8a19401bd401 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_3.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.368,20.429m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.437,18.343m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.94,6.009m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.435,11.853m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.119,17.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_30.xml b/core/res/res/drawable/pointer_wait_vector_30.xml new file mode 100644 index 000000000000..56dcdc228401 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_30.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M17.479,18.415m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12.441,20.425m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.796,13.969m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.586,7.974m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.184,4.047m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M15.092,4.151m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.414,7.975m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.281,13.61m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_31.xml b/core/res/res/drawable/pointer_wait_vector_31.xml new file mode 100644 index 000000000000..5687a9b46b67 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_31.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M17.807,18.12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M13.028,20.373m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.832,14.112m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.517,8.104m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.908,4.15m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M14.817,4.047m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.269,7.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.344,13.247m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_32.xml b/core/res/res/drawable/pointer_wait_vector_32.xml new file mode 100644 index 000000000000..cb626e41d1d5 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_32.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M18.17,17.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M13.61,20.281m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.87,14.254m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.417,8.302m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.704,4.234m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M14.537,3.954m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.076,7.405m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.397,12.809m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_33.xml b/core/res/res/drawable/pointer_wait_vector_33.xml new file mode 100644 index 000000000000..052f973f2ab4 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_33.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M18.51,17.366m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M14.183,20.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.954,14.537m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.323,8.501m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.435,4.354m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M14.184,3.851m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.868,7.101m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.428,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_34.xml b/core/res/res/drawable/pointer_wait_vector_34.xml new file mode 100644 index 000000000000..9e665756f4c2 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_34.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M18.911,16.839m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M14.885,19.928m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.999,14.677m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.206,8.771m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.17,4.483m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M13.826,3.764m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.603,6.748m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.433,11.779m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_35.xml b/core/res/res/drawable/pointer_wait_vector_35.xml new file mode 100644 index 000000000000..1d063fc9fbb9 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_35.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M19.232,16.345m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M15.566,19.646m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.098,14.955m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.098,9.045m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.846,4.657m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M13.465,3.692m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.27,6.355m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.41,11.338m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_36.xml b/core/res/res/drawable/pointer_wait_vector_36.xml new file mode 100644 index 000000000000..db0ad1c847bc --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_36.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M19.583,15.698m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.345,19.232m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.205,15.229m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.999,9.323m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.592,4.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M13.028,3.626m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.035m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.344,10.753m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_37.xml b/core/res/res/drawable/pointer_wait_vector_37.xml new file mode 100644 index 000000000000..ee944a6ccbe6 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_37.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M19.876,15.023m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.077,18.738m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.323,15.499m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.911,9.604m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.221,5.047m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12.589,3.584m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.59,5.681m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.236,10.174m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_38.xml b/core/res/res/drawable/pointer_wait_vector_38.xml new file mode 100644 index 000000000000..a347a36e34b0 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_38.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M20.129,14.255m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.861,18.069m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.45,15.764m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.796,10.031m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.864,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12.147,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.136,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.046,9.463m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_39.xml b/core/res/res/drawable/pointer_wait_vector_39.xml new file mode 100644 index 000000000000..2c86f0dd7849 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_39.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M20.321,13.392m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.557,17.309m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.586,16.026m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.705,10.462m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.521,5.585m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.559,3.575m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.657,4.965m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.766,8.704m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_4.xml b/core/res/res/drawable/pointer_wait_vector_4.xml new file mode 100644 index 000000000000..a6690c003c4b --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_4.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.441,20.425m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.493,18.391m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.914,5.983m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.433,11.772m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.17,17.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_40.xml b/core/res/res/drawable/pointer_wait_vector_40.xml new file mode 100644 index 000000000000..953fdc1deb23 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_40.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M20.428,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.232,16.345m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.731,16.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.656,10.753m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.193,5.88m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.972,3.626m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.026,4.586m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.449,8.039m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_41.xml b/core/res/res/drawable/pointer_wait_vector_41.xml new file mode 100644 index 000000000000..a1b17fa2d19d --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_41.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M20.41,11.338m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.766,15.296m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.924,16.595m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.602,11.191m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.83,6.246m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.39,3.719m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M15.364,4.263m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.994,7.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_42.xml b/core/res/res/drawable/pointer_wait_vector_42.xml new file mode 100644 index 000000000000..4de9b8d14dd8 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_42.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M20.244,10.21m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.14,14.219m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.153,16.929m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.571,11.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.49,6.634m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.817,3.851m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M14.677,4m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.367,6.465m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_43.xml b/core/res/res/drawable/pointer_wait_vector_43.xml new file mode 100644 index 000000000000..38187fe62ac4 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_43.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M19.94,9.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.365,13.101m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.397,17.252m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.566,12.221m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.089,7.161m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.115,4.072m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M13.826,3.763m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.645,5.73m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_44.xml b/core/res/res/drawable/pointer_wait_vector_44.xml new file mode 100644 index 000000000000..890ba7ee6533 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_44.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M19.466,8.072m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.436,12.073m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.73,17.645m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.589,12.662m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.768,7.655m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.368,4.385m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12.882,3.61m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.839,5.089m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_45.xml b/core/res/res/drawable/pointer_wait_vector_45.xml new file mode 100644 index 000000000000..309ac082edef --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_45.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M18.847,7.071m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.382,11.045m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.139,18.069m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.656,13.247m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.417,8.302m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.592,4.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.853,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M15.83,4.483m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_46.xml b/core/res/res/drawable/pointer_wait_vector_46.xml new file mode 100644 index 000000000000..5a9bf706064a --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_46.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M18.195,6.273m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.237,10.174m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.465,18.367m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.797,13.969m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.124,8.977m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.864,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.826,3.646m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M14.747,4.023m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_47.xml b/core/res/res/drawable/pointer_wait_vector_47.xml new file mode 100644 index 000000000000..0068f27c78d5 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_47.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M17.451,5.561m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.046,9.463m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.922,18.738m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.954,14.537m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.851,9.817m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.087,5.983m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.675,3.89m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M13.61,3.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_48.xml b/core/res/res/drawable/pointer_wait_vector_48.xml new file mode 100644 index 000000000000..6ece990ad516 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_48.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M16.748,5.026m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.822,8.84m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.405,19.076m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.205,15.229m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.667,10.68m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.397,6.748m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.569,4.293m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12.588,3.584m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_49.xml b/core/res/res/drawable/pointer_wait_vector_49.xml new file mode 100644 index 000000000000..d44438975224 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_49.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M16.09,4.621m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.583,8.302m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.974,19.414m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.586,16.025m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.571,11.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.768,7.655m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.655,4.768m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.558,3.575m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_5.xml b/core/res/res/drawable/pointer_wait_vector_5.xml new file mode 100644 index 000000000000..4952fe57397b --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_5.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.515,20.421m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.577,18.463m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.877,5.947m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.433,11.779m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.22,17.7m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_50.xml b/core/res/res/drawable/pointer_wait_vector_50.xml new file mode 100644 index 000000000000..a85155fc5dd2 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_50.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M15.499,4.323m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.343,7.846m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.636,19.737m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.047,16.778m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.589,12.662m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.234,8.704m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.634,5.49m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.608,3.679m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_51.xml b/core/res/res/drawable/pointer_wait_vector_51.xml new file mode 100644 index 000000000000..95b4aaa2365a --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_51.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M14.885,4.072m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.155,7.529m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.393,20.024m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.585,17.479m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.748,13.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.851,9.817m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.88,6.193m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.816,3.851m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_52.xml b/core/res/res/drawable/pointer_wait_vector_52.xml new file mode 100644 index 000000000000..34619b5d4361 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_52.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M14.396,3.911m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.953,7.221m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.246,20.252m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.3,18.22m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.072,14.885m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.636,10.899m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.307,6.864m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.114,4.072m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_53.xml b/core/res/res/drawable/pointer_wait_vector_53.xml new file mode 100644 index 000000000000..926b63998470 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_53.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.969,3.797m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.782,6.982m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.118,20.39m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.221,18.953m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.551,15.961m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.564,11.927m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.807,7.592m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.568,4.293m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_54.xml b/core/res/res/drawable/pointer_wait_vector_54.xml new file mode 100644 index 000000000000..c51851fce837 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_54.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.61,3.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.603,6.748m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12.147,20.435m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.17,19.517m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.132,16.899m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.618,12.955m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.45,8.236m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.104,4.517m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_55.xml b/core/res/res/drawable/pointer_wait_vector_55.xml new file mode 100644 index 000000000000..cdf435fa0637 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_55.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.247,3.656m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.463,6.577m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M13.247,20.344m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.253,19.977m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.83,17.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.748,13.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.178,8.84m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.686,4.749m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_56.xml b/core/res/res/drawable/pointer_wait_vector_56.xml new file mode 100644 index 000000000000..1528711e2542 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_56.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M13.028,3.626m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.319,6.41m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M14.325,20.11m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.39,20.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.521,18.415m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.954,14.537m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.976,9.393m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.405,4.924m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_57.xml b/core/res/res/drawable/pointer_wait_vector_57.xml new file mode 100644 index 000000000000..1715db1e2bef --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_57.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.772,3.599m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.22,6.3m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M15.431,19.707m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.411,20.416m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.282,18.994m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.178,15.16m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.851,9.817m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.041,5.175m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_58.xml b/core/res/res/drawable/pointer_wait_vector_58.xml new file mode 100644 index 000000000000..83aec4b24851 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_58.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.589,3.584m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.12,6.193m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.471,19.155m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12.442,20.425m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M7.974,19.414m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.417,15.698m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.748,10.246m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.864,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_59.xml b/core/res/res/drawable/pointer_wait_vector_59.xml new file mode 100644 index 000000000000..2e5e4728ec85 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_59.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.442,3.575m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.069,6.139m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.309,18.556m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M13.465,20.308m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M8.568,19.707m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.657,16.154m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.679,10.608m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.634,5.49m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_6.xml b/core/res/res/drawable/pointer_wait_vector_6.xml new file mode 100644 index 000000000000..d4f57af49b40 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_6.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.588,20.416m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.633,18.51m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.926,3.564m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.861,5.931m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.431,11.706m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.269,17.645m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_60.xml b/core/res/res/drawable/pointer_wait_vector_60.xml new file mode 100644 index 000000000000..4f257671d25d --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_60.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.294,3.569m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.069,6.139m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.12,17.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M14.183,20.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.115,19.928m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M4.845,16.471m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.646,10.826m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.465,5.633m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_61.xml b/core/res/res/drawable/pointer_wait_vector_61.xml new file mode 100644 index 000000000000..7e06db4d1874 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_61.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.147,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.017,6.087m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.738,17.077m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M14.885,19.928m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M9.604,20.089m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.047,16.779m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.61,11.118m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.355,5.73m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_62.xml b/core/res/res/drawable/pointer_wait_vector_62.xml new file mode 100644 index 000000000000..b3d0541a6417 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_62.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.074,3.564m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.231,16.345m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M15.432,19.707m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.102,20.22m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.307,17.136m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.584,11.411m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.246,5.83m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_63.xml b/core/res/res/drawable/pointer_wait_vector_63.xml new file mode 100644 index 000000000000..ee09c2537d3f --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_63.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.583,15.698m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M15.961,19.449m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.39,20.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.397,17.252m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.575,11.558m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.193,5.88m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_64.xml b/core/res/res/drawable/pointer_wait_vector_64.xml new file mode 100644 index 000000000000..e87f94f33304 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_64.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M19.822,15.16m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.345,19.232m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.826,20.354m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.537,17.423m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.571,11.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.139,5.931m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_65.xml b/core/res/res/drawable/pointer_wait_vector_65.xml new file mode 100644 index 000000000000..b8407c448db5 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_65.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.023,14.607m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.718,18.994m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M10.972,20.374m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.681,17.59m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.569,11.706m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.087,5.983m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_66.xml b/core/res/res/drawable/pointer_wait_vector_66.xml new file mode 100644 index 000000000000..7e2448df4d11 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_66.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.149,14.184m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M16.959,18.825m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.265,20.405m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.78,17.7m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.565,11.853m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_67.xml b/core/res/res/drawable/pointer_wait_vector_67.xml new file mode 100644 index 000000000000..615ac04c40b3 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_67.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.252,13.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.194,18.648m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.412,20.416m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.88,17.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_68.xml b/core/res/res/drawable/pointer_wait_vector_68.xml new file mode 100644 index 000000000000..0ba4634a131f --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_68.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.308,13.465m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.366,18.51m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.632,20.429m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.931,17.861m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_69.xml b/core/res/res/drawable/pointer_wait_vector_69.xml new file mode 100644 index 000000000000..efa90bf9df22 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_69.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.354,13.174m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.535,18.367m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.706,20.432m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.931,17.86m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_7.xml b/core/res/res/drawable/pointer_wait_vector_7.xml new file mode 100644 index 000000000000..86d571a40f73 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_7.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.661,20.411m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.69,18.556m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.024,6.045m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.889,3.564m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.808,5.88m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.428,11.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.318,17.59m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_70.xml b/core/res/res/drawable/pointer_wait_vector_70.xml new file mode 100644 index 000000000000..4e58af5dfb3b --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_70.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.39,12.882m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.645,18.27m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.853,20.435m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_71.xml b/core/res/res/drawable/pointer_wait_vector_71.xml new file mode 100644 index 000000000000..5a534342ec8d --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_71.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.416,12.589m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.754,18.17m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.853,20.435m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_72.xml b/core/res/res/drawable/pointer_wait_vector_72.xml new file mode 100644 index 000000000000..40fb5d313f7c --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_72.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.425,12.442m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.807,18.12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_73.xml b/core/res/res/drawable/pointer_wait_vector_73.xml new file mode 100644 index 000000000000..933cc6ae4813 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_73.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.429,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.861,18.069m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_74.xml b/core/res/res/drawable/pointer_wait_vector_74.xml new file mode 100644 index 000000000000..6c7fef264f81 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_74.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.431,12.294m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_75.xml b/core/res/res/drawable/pointer_wait_vector_75.xml new file mode 100644 index 000000000000..24e64e3491cf --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_75.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.435,12.147m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_76.xml b/core/res/res/drawable/pointer_wait_vector_76.xml new file mode 100644 index 000000000000..2ede57de05fd --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_76.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.436,12.073m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_77.xml b/core/res/res/drawable/pointer_wait_vector_77.xml new file mode 100644 index 000000000000..71f811a497a0 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_77.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.436,12.037m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_78.xml b/core/res/res/drawable/pointer_wait_vector_78.xml new file mode 100644 index 000000000000..e2d56c6f676e --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_78.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.437,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_79.xml b/core/res/res/drawable/pointer_wait_vector_79.xml new file mode 100644 index 000000000000..e2d56c6f676e --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_79.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.437,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_8.xml b/core/res/res/drawable/pointer_wait_vector_8.xml new file mode 100644 index 000000000000..ebac74961497 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_8.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.808,20.398m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.806,18.648m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.008,6.061m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.853,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.754,5.83m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.425,11.558m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.367,17.535m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_80.xml b/core/res/res/drawable/pointer_wait_vector_80.xml new file mode 100644 index 000000000000..40fb5d313f7c --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_80.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.425,12.442m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.807,18.12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_81.xml b/core/res/res/drawable/pointer_wait_vector_81.xml new file mode 100644 index 000000000000..933cc6ae4813 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_81.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.429,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.861,18.069m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_82.xml b/core/res/res/drawable/pointer_wait_vector_82.xml new file mode 100644 index 000000000000..6c7fef264f81 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_82.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.431,12.294m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_83.xml b/core/res/res/drawable/pointer_wait_vector_83.xml new file mode 100644 index 000000000000..24e64e3491cf --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_83.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.435,12.147m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_84.xml b/core/res/res/drawable/pointer_wait_vector_84.xml new file mode 100644 index 000000000000..2ede57de05fd --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_84.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.436,12.073m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_85.xml b/core/res/res/drawable/pointer_wait_vector_85.xml new file mode 100644 index 000000000000..71f811a497a0 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_85.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.436,12.037m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_86.xml b/core/res/res/drawable/pointer_wait_vector_86.xml new file mode 100644 index 000000000000..e2d56c6f676e --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_86.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.437,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_87.xml b/core/res/res/drawable/pointer_wait_vector_87.xml new file mode 100644 index 000000000000..e2d56c6f676e --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_87.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.437,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_9.xml b/core/res/res/drawable/pointer_wait_vector_9.xml new file mode 100644 index 000000000000..d46dfa394c01 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_9.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12.881,20.39m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M6.864,18.693m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M3.563,12.052m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M5.983,6.087m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M11.816,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M17.754,5.83m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M20.423,11.522m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> + <path + android:pathData="M18.415,17.479m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0" + android:fillColor="#FFF"/> +</vector> diff --git a/core/res/res/drawable/pointer_wait_vector_icon.xml b/core/res/res/drawable/pointer_wait_vector_icon.xml new file mode 100644 index 000000000000..45d371e95c5d --- /dev/null +++ b/core/res/res/drawable/pointer_wait_vector_icon.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android" + android:bitmap="@drawable/pointer_wait_vector" + android:hotSpotX="12dp" + android:hotSpotY="12dp" /> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index c1fd61948e68..48cf09a84e57 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4409,7 +4409,7 @@ <attr name="requireDeviceScreenOn" format="boolean"/> <!-- Whether the device should default to observe mode when this service is default or in the foreground. --> - <attr name="defaultToObserveMode" format="boolean"/> + <attr name="shouldDefaultToObserveMode" format="boolean"/> </declare-styleable> <!-- Use <code>offhost-apdu-service</code> as the root tag of the XML resource that @@ -4436,7 +4436,7 @@ <attr name="requireDeviceScreenOn"/> <!-- Whether the device should default to observe mode when this service is default or in the foreground. --> - <attr name="defaultToObserveMode"/> + <attr name="shouldDefaultToObserveMode"/> </declare-styleable> <!-- Specify one or more <code>aid-group</code> elements inside a diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index b2e0be7c2201..c882938b63ce 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1618,15 +1618,13 @@ <!-- Data (photo, file, account) upload/download, backup/restore, import/export, fetch, transfer over network between device and cloud. - <p><b>THIS TYPE IS DEPRECATED.</b> - <p><em>Note: For apps with <code>targetSdkVersion</code> - {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} and above, this type should - <b>NOT</b> be used: calling - {@link android.app.Service#startForeground(int, android.app.Notification, int)} - with this type on devices running - {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} is still allowed, but it may - throw an {@link android.app.InvalidForegroundServiceTypeException} in future platform - releases.</em> + <p>For apps with <code>targetSdkVersion</code> + {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, this type should NOT + be used: calling + {@link android.app.Service#startForeground(int, android.app.Notification, int)} with + this type on devices running {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} + is still allowed, but calling it with this type on devices running future platform + releases may get a {@link android.app.InvalidForegroundServiceTypeException}. --> <flag name="dataSync" value="0x01" /> <!-- Music, video, news or other media play. diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 1f06b0b7c62b..6134e788be82 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -6967,4 +6967,16 @@ <!-- Whether to use file hashes cache in watchlist--> <bool name="config_watchlistUseFileHashesCache">false</bool> + + <!-- Name of the package responsible to handle Contextual Search. --> + <string name="config_defaultContextualSearchPackageName" translatable="false" /> + + <!-- The key containing the entrypoint for Contextual Search. --> + <string name="config_defaultContextualSearchKey" translatable="false" /> + + <!-- The key containing the branching boolean for Contextual Search. --> + <string name="config_defaultContextualSearchEnabled" translatable="false" /> + + <!-- The key containing the branching boolean for legacy Search. --> + <string name="config_defaultContextualSearchLegacyEnabled" translatable="false" /> </resources> diff --git a/core/res/res/values/config_battery_saver.xml b/core/res/res/values/config_battery_saver.xml index e1b0ef4bd0a7..551cd0a87867 100644 --- a/core/res/res/values/config_battery_saver.xml +++ b/core/res/res/values/config_battery_saver.xml @@ -33,6 +33,9 @@ <!-- Whether or not battery saver should be "sticky" when manually enabled. --> <bool name="config_batterySaverStickyBehaviourDisabled">false</bool> + <!-- Whether to enable "Battery Saver turned off" notification. --> + <bool name="config_batterySaverTurnedOffNotificationEnabled">true</bool> + <!-- Config flag to track default disable threshold for Dynamic power savings enabled battery saver. --> <integer name="config_dynamicPowerSavingsDefaultDisableThreshold">80</integer> diff --git a/core/res/res/values/config_display.xml b/core/res/res/values/config_display.xml new file mode 100644 index 000000000000..2e66060926fd --- /dev/null +++ b/core/res/res/values/config_display.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright (C) 2024 The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- Resources used in DisplayManager. + + These resources are around just to allow their values to be customized + for different hardware and product builds. Do not translate. + + NOTE: The naming convention is "config_camelCaseValue". --> + + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Whether even dimmer feature is enabled. --> + <bool name="config_evenDimmerEnabled">false</bool> + +</resources> diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index 104b7cd5450b..c87b7cdb1e8e 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -73,6 +73,11 @@ <bool name="auto_data_switch_ping_test_before_switch">true</bool> <java-symbol type="bool" name="auto_data_switch_ping_test_before_switch" /> + <!-- TODO: remove after V --> + <!-- Boolean indicating whether allow to use a roaming nonDDS if user enabled its roaming. --> + <bool name="auto_data_switch_allow_roaming">true</bool> + <java-symbol type="bool" name="auto_data_switch_allow_roaming" /> + <!-- Define the tolerated gap of score for auto data switch decision, larger than which the device will switch to the SIM with higher score. The score is used in conjunction with the score table defined in diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index 5987f6ea05d4..3303c076c090 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -160,7 +160,7 @@ <!-- @FlaggedApi("android.view.inputmethod.connectionless_handwriting") --> <public name="supportsConnectionlessStylusHandwriting" /> <!-- @FlaggedApi("android.nfc.Flags.FLAG_OBSERVE_MODE") --> - <public name="defaultToObserveMode"/> + <public name="shouldDefaultToObserveMode"/> <!-- @FlaggedApi("android.security.asm_restrictions_enabled") --> <public name="allowCrossUidActivitySwitchFromBelow"/> <!-- @FlaggedApi("com.android.text.flags.use_bounds_for_width") --> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index adf8d9f95b52..5945f81704c5 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1468,7 +1468,7 @@ please see styles_device_defaults.xml. <item name="pointerIconHand">@drawable/pointer_hand_vector_icon</item> <item name="pointerIconContextMenu">@drawable/pointer_context_menu_vector_icon</item> <item name="pointerIconHelp">@drawable/pointer_help_vector_icon</item> - <item name="pointerIconWait">@drawable/pointer_wait_icon</item> + <item name="pointerIconWait">@drawable/pointer_wait_vector_icon</item> <item name="pointerIconCell">@drawable/pointer_cell_vector_icon</item> <item name="pointerIconCrosshair">@drawable/pointer_crosshair_vector_icon</item> <item name="pointerIconText">@drawable/pointer_text_vector_icon</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 3284791ef384..2f5183fc1455 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4123,6 +4123,7 @@ <java-symbol type="bool" name="config_batterySaverSupported" /> <java-symbol type="string" name="config_batterySaverDeviceSpecificConfig" /> <java-symbol type="bool" name="config_batterySaverStickyBehaviourDisabled" /> + <java-symbol type="bool" name="config_batterySaverTurnedOffNotificationEnabled" /> <java-symbol type="integer" name="config_dynamicPowerSavingsDefaultDisableThreshold" /> <java-symbol type="string" name="config_batterySaverScheduleProvider" /> <java-symbol type="string" name="config_powerSaveModeChangedListenerPackage" /> @@ -5363,5 +5364,12 @@ <java-symbol type="string" name="satellite_notification_how_it_works" /> <java-symbol type="drawable" name="ic_satellite_alt_24px" /> + <!-- DisplayManager configs. --> + <java-symbol type="bool" name="config_evenDimmerEnabled" /> + <java-symbol type="bool" name="config_watchlistUseFileHashesCache" /> + <java-symbol type="string" name="config_defaultContextualSearchPackageName" /> + <java-symbol type="string" name="config_defaultContextualSearchKey" /> + <java-symbol type="string" name="config_defaultContextualSearchEnabled" /> + <java-symbol type="string" name="config_defaultContextualSearchLegacyEnabled" /> </resources> diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 37e6780a8109..e72beee71e50 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -28,10 +28,19 @@ filegroup { visibility: ["//visibility:private"], } +java_defaults { + name: "FrameworksCoreTests-resources", + aaptflags: [ + "-0 .dat", + "-0 .gld", + "-c fa", + ], + resource_dirs: ["res"], +} + android_test { name: "FrameworksCoreTests", - // FrameworksCoreTestsRavenwood references the .aapt.srcjar - use_resource_processor: false, + defaults: ["FrameworksCoreTests-resources"], srcs: [ "src/**/*.java", @@ -117,7 +126,6 @@ android_test { certificate: "platform", - resource_dirs: ["res"], resource_zips: [":FrameworksCoreTests_apks_as_resources"], java_resources: [":FrameworksCoreTests_unit_test_cert_der"], @@ -128,6 +136,24 @@ android_test { ], } +// FrameworksCoreTestsRavenwood pulls in the R.java class from this one. +// Note, "FrameworksCoreTests" and "FrameworksCoreTests-resonly" _might_ not have indentical +// R.java (not sure if there's a guarantee), but that doesn't matter as long as +// FrameworksCoreTestsRavenwood consistently uses the R definition in this module. +android_app { + name: "FrameworksCoreTests-resonly", + defaults: ["FrameworksCoreTests-resources"], + + // FrameworksCoreTestsRavenwood references the .aapt.srcjar + use_resource_processor: false, + libs: [ + "framework-res", + "android.test.runner", + "org.apache.http.legacy", + ], + sdk_version: "core_platform", +} + // Rules to copy all the test apks to the intermediate raw resource directory java_genrule { name: "FrameworksCoreTests_apks_as_resources", @@ -225,7 +251,11 @@ android_ravenwood_test { "src/com/android/internal/util/**/*.java", "src/com/android/internal/power/EnergyConsumerStatsTest.java", - ":FrameworksCoreTests{.aapt.srcjar}", + // Pull in R.java from FrameworksCoreTests-resonly, not from FrameworksCoreTests, + // to avoid having a dependency to FrameworksCoreTests. + // This way, when updating source files and running this test, we don't need to + // rebuild the entire FrameworksCoreTests, which would be slow. + ":FrameworksCoreTests-resonly{.aapt.srcjar}", ":FrameworksCoreTests-aidl", ":FrameworksCoreTests-helpers", ":FrameworksCoreTestDoubles-sources", diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index a7d083cbc399..64c17bdfa731 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -65,6 +65,7 @@ import android.util.DisplayMetrics; import android.util.MergedConfiguration; import android.view.Display; import android.view.View; +import android.window.ActivityWindowInfo; import android.window.WindowContextInfo; import android.window.WindowTokenClientController; @@ -394,11 +395,13 @@ public class ActivityThreadTest { olderConfig.seq = seq + 1; final ActivityClientRecord r = getActivityClientRecord(activity); - activityThread.handleActivityConfigurationChanged(r, olderConfig, INVALID_DISPLAY); + activityThread.handleActivityConfigurationChanged(r, olderConfig, INVALID_DISPLAY, + new ActivityWindowInfo()); assertEquals(numOfConfig, activity.mNumOfConfigChanges); assertEquals(olderConfig.orientation, activity.mConfig.orientation); - activityThread.handleActivityConfigurationChanged(r, newerConfig, INVALID_DISPLAY); + activityThread.handleActivityConfigurationChanged(r, newerConfig, INVALID_DISPLAY, + new ActivityWindowInfo()); assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges); assertEquals(newerConfig.orientation, activity.mConfig.orientation); }); @@ -416,7 +419,7 @@ public class ActivityThreadTest { config.orientation = ORIENTATION_PORTRAIT; activityThread.handleActivityConfigurationChanged(getActivityClientRecord(activity), - config, INVALID_DISPLAY); + config, INVALID_DISPLAY, new ActivityWindowInfo()); }); final IApplicationThread appThread = activityThread.getApplicationThread(); @@ -487,7 +490,7 @@ public class ActivityThreadTest { config.orientation = ORIENTATION_PORTRAIT; activityThread.handleActivityConfigurationChanged(getActivityClientRecord(activity), - config, INVALID_DISPLAY); + config, INVALID_DISPLAY, new ActivityWindowInfo()); }); final int numOfConfig = activity.mNumOfConfigChanges; @@ -617,7 +620,7 @@ public class ActivityThreadTest { activityThread.updatePendingActivityConfiguration(activity.getActivityToken(), newActivityConfig); activityThread.handleActivityConfigurationChanged(r, newActivityConfig, - INVALID_DISPLAY); + INVALID_DISPLAY, new ActivityWindowInfo()); assertEquals("Virtual display orientation must not change when activity" + " configuration orientation changes.", @@ -782,8 +785,8 @@ public class ActivityThreadTest { /** * Calls {@link ActivityThread#handleActivityConfigurationChanged(ActivityClientRecord, - * Configuration, int)} to try to push activity configuration to the activity for the given - * sequence number. + * Configuration, int, ActivityWindowInfo)} to try to push activity configuration to the + * activity for the given sequence number. * <p> * It uses orientation to push the configuration and it tries a different orientation if the * first attempt doesn't make through, to rule out the possibility that the previous @@ -802,7 +805,8 @@ public class ActivityThreadTest { Configuration config = new Configuration(); config.orientation = ORIENTATION_PORTRAIT; config.seq = seq; - activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY); + activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY, + new ActivityWindowInfo()); if (activity.mNumOfConfigChanges > numOfConfig) { return config.seq; @@ -811,7 +815,8 @@ public class ActivityThreadTest { config = new Configuration(); config.orientation = ORIENTATION_LANDSCAPE; config.seq = seq + 1; - activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY); + activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY, + new ActivityWindowInfo()); return config.seq; } @@ -839,7 +844,7 @@ public class ActivityThreadTest { final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain( activity.getActivityToken(), null, null, 0, new MergedConfiguration(currentConfig, currentConfig), - false /* preserveWindow */); + false /* preserveWindow */, new ActivityWindowInfo()); final ResumeActivityItem resumeStateRequest = ResumeActivityItem.obtain(activity.getActivityToken(), true /* isForward */, false /* shouldSendCompatFakeFocus*/); diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java index b5e8203c51ed..85a1b4ee3ebd 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java +++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java @@ -40,6 +40,7 @@ import android.util.ArrayMap; import android.util.MergedConfiguration; import android.view.IWindow; import android.view.InsetsState; +import android.window.ActivityWindowInfo; import android.window.ClientWindowFrames; import android.window.WindowContext; import android.window.WindowContextInfo; @@ -116,7 +117,8 @@ public class ClientTransactionItemTest { public void testActivityRelaunchItem_getContextToUpdate() { final ActivityRelaunchItem item = ActivityRelaunchItem .obtain(mActivityToken, null /* pendingResults */, null /* pendingNewIntents */, - 0 /* configChange */, mMergedConfiguration, false /* preserveWindow */); + 0 /* configChange */, mMergedConfiguration, false /* preserveWindow */, + new ActivityWindowInfo()); final Context context = item.getContextToUpdate(mHandler); assertEquals(mActivity, context); @@ -175,7 +177,7 @@ public class ClientTransactionItemTest { @Test public void testMoveToDisplayItem_getContextToUpdate() { final MoveToDisplayItem item = MoveToDisplayItem - .obtain(mActivityToken, DEFAULT_DISPLAY, mConfiguration); + .obtain(mActivityToken, DEFAULT_DISPLAY, mConfiguration, new ActivityWindowInfo()); final Context context = item.getContextToUpdate(mHandler); assertEquals(mActivity, context); diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java index c6447be71855..906558f7603b 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java @@ -39,6 +39,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.PersistableBundle; import android.platform.test.annotations.Presubmit; +import android.window.ActivityWindowInfo; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -124,6 +125,7 @@ public class ObjectPoolTests { final int deviceId = 3; final IBinder taskFragmentToken = new Binder(); final IBinder initialCallerInfoAccessToken = new Binder(); + final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo(); testRecycle(() -> new LaunchActivityItemBuilder( activityToken, intent, activityInfo) @@ -142,18 +144,21 @@ public class ObjectPoolTests { .setTaskFragmentToken(taskFragmentToken) .setDeviceId(deviceId) .setInitialCallerInfoAccessToken(initialCallerInfoAccessToken) + .setActivityWindowInfo(activityWindowInfo) .build()); } @Test public void testRecycleActivityRelaunchItem() { testRecycle(() -> ActivityRelaunchItem.obtain(mActivityToken, - resultInfoList(), referrerIntentList(), 42, mergedConfig(), true)); + resultInfoList(), referrerIntentList(), 42, mergedConfig(), true, + new ActivityWindowInfo())); } @Test public void testRecycleMoveToDisplayItem() { - testRecycle(() -> MoveToDisplayItem.obtain(mActivityToken, 4, config())); + testRecycle(() -> MoveToDisplayItem.obtain(mActivityToken, 4, config(), + new ActivityWindowInfo())); } @Test diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java index d641659e6a5f..c1b9efda4652 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java +++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java @@ -32,6 +32,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.PersistableBundle; import android.util.MergedConfiguration; +import android.window.ActivityWindowInfo; import com.android.internal.app.IVoiceInteractor; import com.android.internal.content.ReferrerIntent; @@ -134,6 +135,8 @@ class TestUtils { private IBinder mTaskFragmentToken; @Nullable private IBinder mInitialCallerInfoAccessToken; + @NonNull + private ActivityWindowInfo mActivityWindowInfo = new ActivityWindowInfo(); LaunchActivityItemBuilder(@NonNull IBinder activityToken, @NonNull Intent intent, @NonNull ActivityInfo info) { @@ -260,6 +263,13 @@ class TestUtils { } @NonNull + LaunchActivityItemBuilder setActivityWindowInfo( + @NonNull ActivityWindowInfo activityWindowInfo) { + mActivityWindowInfo.set(activityWindowInfo); + return this; + } + + @NonNull LaunchActivityItem build() { return LaunchActivityItem.obtain(mActivityToken, mIntent, mIdent, mInfo, mCurConfig, mOverrideConfig, mDeviceId, mReferrer, mVoiceInteractor, @@ -267,7 +277,7 @@ class TestUtils { mActivityOptions != null ? mActivityOptions.getSceneTransitionInfo() : null, mIsForward, mProfilerInfo, mAssistToken, null /* activityClientController */, mShareableActivityToken, mLaunchedFromBubble, mTaskFragmentToken, - mInitialCallerInfoAccessToken); + mInitialCallerInfoAccessToken, mActivityWindowInfo); } } } diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java index aa8001310008..dbb090fe795b 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java @@ -32,6 +32,7 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.Configuration; +import android.graphics.Rect; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; @@ -40,6 +41,7 @@ import android.os.Parcelable; import android.os.PersistableBundle; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; +import android.window.ActivityWindowInfo; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -108,8 +110,11 @@ public class TransactionParcelTests { @Test public void testMoveToDisplay() { // Write to parcel + final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo(); + activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 500, 1000), + new Rect(0, 0, 500, 500)); MoveToDisplayItem item = MoveToDisplayItem.obtain(mActivityToken, 4 /* targetDisplayId */, - config()); + config(), activityWindowInfo); writeAndPrepareForReading(item); // Read from parcel and assert @@ -180,6 +185,9 @@ public class TransactionParcelTests { bundle.putParcelable("data", new ParcelableData(1)); final PersistableBundle persistableBundle = new PersistableBundle(); persistableBundle.putInt("k", 4); + final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo(); + activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 500, 1000), + new Rect(0, 0, 500, 500)); final LaunchActivityItem item = new LaunchActivityItemBuilder( activityToken, intent, activityInfo) @@ -198,6 +206,7 @@ public class TransactionParcelTests { .setShareableActivityToken(new Binder()) .setTaskFragmentToken(new Binder()) .setInitialCallerInfoAccessToken(new Binder()) + .setActivityWindowInfo(activityWindowInfo) .build(); writeAndPrepareForReading(item); @@ -214,8 +223,11 @@ public class TransactionParcelTests { // Write to parcel Configuration overrideConfig = new Configuration(); overrideConfig.assetsSeq = 5; + final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo(); + activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 500, 1000), + new Rect(0, 0, 500, 500)); ActivityRelaunchItem item = ActivityRelaunchItem.obtain(mActivityToken, resultInfoList(), - referrerIntentList(), 35, mergedConfig(), true); + referrerIntentList(), 35, mergedConfig(), true, activityWindowInfo); writeAndPrepareForReading(item); // Read from parcel and assert diff --git a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java index 3ee565f8e025..e118c98dd4da 100644 --- a/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java +++ b/core/tests/coretests/src/android/database/sqlite/SQLiteDatabaseTest.java @@ -403,41 +403,4 @@ public class SQLiteDatabaseTest { } assertFalse(allowed); } - - /** Return true if the path is in the list of strings. */ - private boolean isConcurrent(String path) throws Exception { - path = new File(path).toPath().toRealPath().toString(); - return SQLiteDatabase.getConcurrentDatabasePaths().contains(path); - } - - @Test - public void testDuplicateDatabases() throws Exception { - // The two database paths in this test are assumed not to have been opened earlier in this - // process. - - // A database path that will be opened twice. - final String dbName = "never-used-db.db"; - final File dbFile = mContext.getDatabasePath(dbName); - final String dbPath = dbFile.getPath(); - - // A database path that will be opened only once. - final String okName = "never-used-ok.db"; - final File okFile = mContext.getDatabasePath(okName); - final String okPath = okFile.getPath(); - - SQLiteDatabase db1 = SQLiteDatabase.openOrCreateDatabase(dbFile, null); - assertFalse(isConcurrent(dbPath)); - SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase(dbFile, null); - assertTrue(isConcurrent(dbPath)); - db1.close(); - assertTrue(isConcurrent(dbPath)); - db2.close(); - assertTrue(isConcurrent(dbPath)); - - SQLiteDatabase db3 = SQLiteDatabase.openOrCreateDatabase(okFile, null); - db3.close(); - db3 = SQLiteDatabase.openOrCreateDatabase(okFile, null); - assertFalse(isConcurrent(okPath)); - db3.close(); - } } diff --git a/core/tests/coretests/src/android/os/WakeLockStatsTest.java b/core/tests/coretests/src/android/os/WakeLockStatsTest.java index 2675ba07d2f7..f3b18c8bd9bb 100644 --- a/core/tests/coretests/src/android/os/WakeLockStatsTest.java +++ b/core/tests/coretests/src/android/os/WakeLockStatsTest.java @@ -29,10 +29,114 @@ import java.util.List; public class WakeLockStatsTest { @Test + public void isDataValidOfWakeLockData_invalid_returnFalse() { + WakeLockStats.WakeLockData wakeLockData = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 0, /* totalTimeHeldMs= */ 10, /* timeHeldMs= */ 0); + assertThat(wakeLockData.isDataValid()).isFalse(); + + wakeLockData = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 1, /* totalTimeHeldMs= */ 0, /* timeHeldMs= */ 0); + assertThat(wakeLockData.isDataValid()).isFalse(); + + wakeLockData = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 1, /* totalTimeHeldMs= */ 10, /* timeHeldMs= */ -10); + assertThat(wakeLockData.isDataValid()).isFalse(); + + wakeLockData = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 1, /* totalTimeHeldMs= */ 10, /* timeHeldMs= */ 20); + assertThat(wakeLockData.isDataValid()).isFalse(); + } + + @Test + public void isDataValidOfWakeLockData_empty_returnTrue() { + final WakeLockStats.WakeLockData wakeLockData = WakeLockStats.WakeLockData.EMPTY; + assertThat(wakeLockData.isDataValid()).isTrue(); + } + + @Test + public void isDataValidOfWakeLockData_valid_returnTrue() { + WakeLockStats.WakeLockData wakeLockData = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 1, /* totalTimeHeldMs= */ 10, /* timeHeldMs= */ 5); + assertThat(wakeLockData.isDataValid()).isTrue(); + } + + @Test + public void isDataValidOfWakeLock_zeroTotalHeldMs_returnFalse() { + final WakeLockStats.WakeLockData wakeLockData = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 0, /* totalTimeHeldMs= */ 0, /* timeHeldMs= */ 0); + + assertThat(WakeLockStats.WakeLock.isDataValid(wakeLockData, wakeLockData)).isFalse(); + } + + @Test + public void isDataValidOfWakeLock_invalidData_returnFalse() { + final WakeLockStats.WakeLockData totalWakeLockData = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 6, /* totalTimeHeldMs= */ 60, /* timeHeldMs= */ 20); + final WakeLockStats.WakeLockData backgroundWakeLockData = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 0, /* totalTimeHeldMs= */ 10, /* timeHeldMs= */ 0); + + assertThat(WakeLockStats.WakeLock.isDataValid(totalWakeLockData, backgroundWakeLockData)) + .isFalse(); + } + + @Test + public void isDataValidOfWakeLock_totalSmallerThanBackground_returnFalse() { + final WakeLockStats.WakeLockData totalWakeLockData = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 10, /* totalTimeHeldMs= */ 60, /* timeHeldMs= */ 50); + final WakeLockStats.WakeLockData backgroundWakeLockData = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 6, /* totalTimeHeldMs= */ 100, /* timeHeldMs= */ 30); + + assertThat(WakeLockStats.WakeLock.isDataValid(totalWakeLockData, backgroundWakeLockData)) + .isFalse(); + } + + @Test + public void isDataValidOfWakeLock_returnTrue() { + final WakeLockStats.WakeLockData totalWakeLockData = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 10, /* totalTimeHeldMs= */ 100, /* timeHeldMs= */ 50); + final WakeLockStats.WakeLockData backgroundWakeLockData = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 6, /* totalTimeHeldMs= */ 60, /* timeHeldMs= */ 20); + + assertThat(WakeLockStats.WakeLock.isDataValid(totalWakeLockData, backgroundWakeLockData)) + .isTrue(); + } + + @Test public void parcelablity() { + final WakeLockStats.WakeLockData totalWakeLockData1 = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 10, /* totalTimeHeldMs= */ 60, /* timeHeldMs= */ 50); + final WakeLockStats.WakeLockData backgroundWakeLockData1 = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 6, /* totalTimeHeldMs= */ 100, /* timeHeldMs= */ 30); + final WakeLockStats.WakeLock wakeLock1 = + new WakeLockStats.WakeLock( + 1, "foo", /* isAggregated= */ false, totalWakeLockData1, + backgroundWakeLockData1); + final WakeLockStats.WakeLockData totalWakeLockData2 = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 20, /* totalTimeHeldMs= */ 80, /* timeHeldMs= */ 30); + final WakeLockStats.WakeLockData backgroundWakeLockData2 = + new WakeLockStats.WakeLockData( + /* timesAcquired= */ 1, /* totalTimeHeldMs= */ 100, /* timeHeldMs= */ 30); + final WakeLockStats.WakeLock wakeLock2 = + new WakeLockStats.WakeLock( + 2, "bar", /* isAggregated= */ true, totalWakeLockData2, + backgroundWakeLockData2); WakeLockStats wakeLockStats = new WakeLockStats( - List.of(new WakeLockStats.WakeLock(1, "foo", 200, 3000, 40000), - new WakeLockStats.WakeLock(2, "bar", 500, 6000, 70000))); + List.of(wakeLock1), List.of(wakeLock2)); Parcel parcel = Parcel.obtain(); wakeLockStats.writeToParcel(parcel, 0); @@ -44,15 +148,28 @@ public class WakeLockStatsTest { parcel.setDataPosition(0); WakeLockStats actual = WakeLockStats.CREATOR.createFromParcel(parcel); - assertThat(actual.getWakeLocks()).hasSize(2); - WakeLockStats.WakeLock wl1 = actual.getWakeLocks().get(0); - assertThat(wl1.uid).isEqualTo(1); - assertThat(wl1.name).isEqualTo("foo"); - assertThat(wl1.timesAcquired).isEqualTo(200); - assertThat(wl1.totalTimeHeldMs).isEqualTo(3000); - assertThat(wl1.timeHeldMs).isEqualTo(40000); - - WakeLockStats.WakeLock wl2 = actual.getWakeLocks().get(1); - assertThat(wl2.uid).isEqualTo(2); - } -} + assertThat(actual.getWakeLocks()).hasSize(1); + WakeLockStats.WakeLock actualWakelock = actual.getWakeLocks().get(0); + assertThat(actualWakelock.uid).isEqualTo(1); + assertThat(actualWakelock.name).isEqualTo("foo"); + assertThat(actualWakelock.isAggregated).isFalse(); + assertThat(actualWakelock.totalWakeLockData.timesAcquired).isEqualTo(10); + assertThat(actualWakelock.totalWakeLockData.totalTimeHeldMs).isEqualTo(60); + assertThat(actualWakelock.totalWakeLockData.timeHeldMs).isEqualTo(50); + assertThat(actualWakelock.backgroundWakeLockData.timesAcquired).isEqualTo(6); + assertThat(actualWakelock.backgroundWakeLockData.totalTimeHeldMs).isEqualTo(100); + assertThat(actualWakelock.backgroundWakeLockData.timeHeldMs).isEqualTo(30); + + assertThat(actual.getAggregatedWakeLocks()).hasSize(1); + WakeLockStats.WakeLock actualAggregatedWakelock = actual.getAggregatedWakeLocks().get(0); + assertThat(actualAggregatedWakelock.uid).isEqualTo(2); + assertThat(actualAggregatedWakelock.name).isEqualTo("bar"); + assertThat(actualAggregatedWakelock.isAggregated).isTrue(); + assertThat(actualAggregatedWakelock.totalWakeLockData.timesAcquired).isEqualTo(20); + assertThat(actualAggregatedWakelock.totalWakeLockData.totalTimeHeldMs).isEqualTo(80); + assertThat(actualAggregatedWakelock.totalWakeLockData.timeHeldMs).isEqualTo(30); + assertThat(actualAggregatedWakelock.backgroundWakeLockData.timesAcquired).isEqualTo(1); + assertThat(actualAggregatedWakelock.backgroundWakeLockData.totalTimeHeldMs).isEqualTo(100); + assertThat(actualAggregatedWakelock.backgroundWakeLockData.timeHeldMs).isEqualTo(30); + } +}
\ No newline at end of file diff --git a/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java b/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java index d57f1fcc6da1..030d420d4b65 100644 --- a/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java +++ b/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java @@ -24,15 +24,15 @@ import static java.io.File.createTempFile; import static java.nio.file.Files.createTempDirectory; import android.internal.perfetto.protos.PerfettoTrace; -import android.tools.common.ScenarioBuilder; -import android.tools.common.Tag; -import android.tools.common.io.TraceType; -import android.tools.device.traces.TraceConfig; -import android.tools.device.traces.TraceConfigs; -import android.tools.device.traces.io.ResultReader; -import android.tools.device.traces.io.ResultWriter; -import android.tools.device.traces.monitors.PerfettoTraceMonitor; -import android.tools.device.traces.monitors.TraceMonitor; +import android.tools.ScenarioBuilder; +import android.tools.Tag; +import android.tools.io.TraceType; +import android.tools.traces.TraceConfig; +import android.tools.traces.TraceConfigs; +import android.tools.traces.io.ResultReader; +import android.tools.traces.io.ResultWriter; +import android.tools.traces.monitors.PerfettoTraceMonitor; +import android.tools.traces.monitors.TraceMonitor; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; diff --git a/core/tests/coretests/src/android/view/RoundedCornersTest.java b/core/tests/coretests/src/android/view/RoundedCornersTest.java index 07ef33af3088..ec665ad042ae 100644 --- a/core/tests/coretests/src/android/view/RoundedCornersTest.java +++ b/core/tests/coretests/src/android/view/RoundedCornersTest.java @@ -16,6 +16,8 @@ package android.view; +import static android.content.res.Configuration.SCREENLAYOUT_ROUND_NO; +import static android.content.res.Configuration.SCREENLAYOUT_ROUND_YES; import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT; import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT; import static android.view.RoundedCorner.POSITION_TOP_LEFT; @@ -28,22 +30,47 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.sameInstance; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.when; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; import android.platform.test.annotations.Presubmit; +import android.util.DisplayMetrics; import android.util.Pair; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.R; + +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) @SmallTest @Presubmit public class RoundedCornersTest { + @Mock + DisplayMetrics mMockDisplayMetrics; + @Mock + Resources mMockResources; + @Mock TypedArray mMockTypedArray; + Configuration mConfiguration; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mConfiguration = Configuration.EMPTY; + } + final RoundedCorners mRoundedCorners = new RoundedCorners( new RoundedCorner(POSITION_TOP_LEFT, 10, 10, 10), new RoundedCorner(POSITION_TOP_RIGHT, 10, 190, 10), @@ -199,4 +226,63 @@ public class RoundedCornersTest { assertThat(RoundedCorners.fromRadii(radius, 200, 300), not(sameInstance(cached))); } + + @Test + public void testGetRoundedCornerRadius_withRoundDevice_usesDisplayRadiusAsDefault() { + final int displayWidth = 400; + mConfiguration.screenLayout = SCREENLAYOUT_ROUND_YES; + mMockDisplayMetrics.widthPixels = displayWidth; + + when(mMockResources.getConfiguration()).thenReturn(mConfiguration); + when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics); + when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray)) + .thenReturn(new String[]{"0"}); + when(mMockTypedArray.length()).thenReturn(0); + when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray); + when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius)) + .thenReturn(0); + + + int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0"); + assertEquals((displayWidth / 2), radius); + } + + @Test + public void testGetRoundedCornerRadius_withRoundDevice_usesOverlayIfProvided() { + final int displayWidth = 400; + final int overlayValue = 199; + mConfiguration.screenLayout = SCREENLAYOUT_ROUND_YES; + mMockDisplayMetrics.widthPixels = displayWidth; + + when(mMockResources.getConfiguration()).thenReturn(mConfiguration); + when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics); + when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray)) + .thenReturn(new String[]{"0"}); + when(mMockTypedArray.length()).thenReturn(0); + when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray); + when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius)) + .thenReturn(overlayValue); + + int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0"); + assertEquals(overlayValue, radius); + } + + @Test + public void testGetRoundedCornerRadius_withNonRoundDevice_noDisplayDefault() { + final int displayWidth = 400; + mConfiguration.screenLayout = SCREENLAYOUT_ROUND_NO; + mMockDisplayMetrics.widthPixels = displayWidth; + + when(mMockResources.getConfiguration()).thenReturn(mConfiguration); + when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics); + when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray)) + .thenReturn(new String[]{"0"}); + when(mMockTypedArray.length()).thenReturn(0); + when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray); + when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius)) + .thenReturn(0); + + int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0"); + assertEquals(0, radius); + } } diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java index 64cbe7f1b079..7c58de67ded6 100644 --- a/core/tests/coretests/src/android/view/ViewRootImplTest.java +++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java @@ -1017,6 +1017,60 @@ public class ViewRootImplTest { assertEquals(viewRootImpl.isFrameRatePowerSavingsBalanced(), true); } + /** + * Test the TextureView heuristic: + * 1. Store the last 3 invalidates time - FT1, FT2, FT3. + * 2. If FT2-FT1 > 15ms && FT3-FT2 > 15ms -> vote for NORMAL category + */ + @Test + @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) + public void votePreferredFrameRate_applyTextureViewHeuristic() throws InterruptedException { + final long delay = 30L; + + TextureView view = new TextureView(sContext); + WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY); + wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check + + sInstrumentation.runOnMainSync(() -> { + WindowManager wm = sContext.getSystemService(WindowManager.class); + Display display = wm.getDefaultDisplay(); + DisplayMetrics metrics = new DisplayMetrics(); + display.getMetrics(metrics); + wmlp.width = (int) (metrics.widthPixels * 0.9); + wmlp.height = (int) (metrics.heightPixels * 0.9); + wm.addView(view, wmlp); + }); + sInstrumentation.waitForIdleSync(); + + ViewRootImpl viewRootImpl = view.getViewRootImpl(); + + sInstrumentation.runOnMainSync(() -> { + assertEquals(viewRootImpl.getPreferredFrameRateCategory(), + FRAME_RATE_CATEGORY_NO_PREFERENCE); + view.invalidate(); + assertEquals(viewRootImpl.getPreferredFrameRateCategory(), + FRAME_RATE_CATEGORY_HIGH); + }); + + // reset the frame rate category counts + for (int i = 0; i < 5; i++) { + Thread.sleep(delay); + sInstrumentation.runOnMainSync(() -> { + view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE); + view.invalidate(); + }); + sInstrumentation.waitForIdleSync(); + } + + Thread.sleep(delay); + sInstrumentation.runOnMainSync(() -> { + view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT); + view.invalidate(); + assertEquals(viewRootImpl.getPreferredFrameRateCategory(), + FRAME_RATE_CATEGORY_NORMAL); + }); + } + @Test public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() { mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR); diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java index 39cb616b1ed9..66be05ff233c 100644 --- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java +++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java @@ -61,6 +61,7 @@ import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.testing.PollingCheck; import android.view.WindowManagerGlobal; +import android.window.ActivityWindowInfo; import android.window.SizeConfigurationBuckets; import androidx.test.annotation.UiThreadTest; @@ -354,7 +355,7 @@ public class ActivityThreadClientTest { null /* activityOptions */, true /* isForward */, null /* profilerInfo */, mThread /* client */, null /* asssitToken */, null /* shareableActivityToken */, false /* launchedFromBubble */, null /* taskfragmentToken */, - null /* initialCallerInfoAccessToken */); + null /* initialCallerInfoAccessToken */, new ActivityWindowInfo()); } @Override diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 1fd10031a129..238a3e10f058 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -199,3 +199,8 @@ filegroup { name: "services.core.protolog.json", srcs: ["services.core.protolog.json"], } + +filegroup { + name: "file-core.protolog.pb", + srcs: ["core.protolog.pb"], +} diff --git a/data/etc/core.protolog.pb b/data/etc/core.protolog.pb Binary files differnew file mode 100644 index 000000000000..0415e44af72a --- /dev/null +++ b/data/etc/core.protolog.pb diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 42e3387e3eb5..e8c7a53ddcff 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1,4715 +1,4709 @@ { "version": "1.0.0", "messages": { - "-2127842445": { - "message": "Clearing startingData for token=%s", + "7286191062634870297": { + "message": "Binding proc %s with config %s", "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/am\/ActivityManagerService.java" + }, + "-4921282642721622589": { + "message": "Report configuration: %s %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityClientController.java" + }, + "-1597980207704427048": { + "message": "Frontmost changed immersion: %s", + "level": "DEBUG", + "group": "WM_DEBUG_IMMERSIVE", + "at": "com\/android\/server\/wm\/ActivityClientController.java" + }, + "-6509265758887333864": { + "message": "Can't report activity moved to display - client not running, activityRecord=%s, displayId=%d", + "level": "WARN", + "group": "WM_DEBUG_SWITCH", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2121056984": { - "message": "%s", + "-4183059578873561863": { + "message": "Reporting activity moved to display, activityRecord=%s, displayId=%d, config=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_SWITCH", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "7435279034964784633": { + "message": "Can't report activity configuration update - client not running, activityRecord=%s", "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2111539867": { - "message": "remove IME snapshot, caller=%s", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "-7418876140361338495": { + "message": "Sending new config to %s, config: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2109936758": { - "message": "removeAppToken make exiting: %s", + "-4284934398288119962": { + "message": "Can't report activity position update - client not running, activityRecord=%s", + "level": "WARN", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "7244227111034368231": { + "message": "Sending position change to %s, onTop: %b", "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", + "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2109864870": { - "message": "app-release(): mOuter=%s", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "338586566486930495": { + "message": "Checking theme of starting window: 0x%x", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2107721178": { - "message": "grantEmbeddedWindowFocus win=%s grantFocus=%s", + "-2561793317091789573": { + "message": "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s", "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2101985723": { - "message": "Failed looking up window session=%s callers=%s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "7269690012594027154": { + "message": "Creating SplashScreenStartingData", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2093859262": { - "message": "setClientVisible: %s clientVisible=%b Callers=%s", + "-3432060893368468911": { + "message": "Creating SnapshotStartingData", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowToken.java" + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2088209279": { - "message": "Notified TransitionController that the display is ready.", + "1789854065584848502": { + "message": "startingData was nulled out before handling mAddStartingWindow: %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2074882083": { - "message": "Content Recording: Unable to retrieve task to start recording for display %d", + "5659016061937922595": { + "message": "Add starting %s: startingData=%s", "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2072089308": { - "message": "Attempted to add window with token that is a sub-window: %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-9066702108316454290": { + "message": "Aborted starting %s: startingData=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2072029833": { - "message": "Content Recording: Found no matching mirror display for id=%d for DEFAULT_DISPLAY. Nothing to mirror.", - "level": "WARN", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "7506106334102501360": { + "message": "Added starting %s: startingWindow=%s startingView=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2054442123": { - "message": "Setting Intent of %s to %s", + "1048048288756547220": { + "message": "Surface returned was null: %s", "level": "VERBOSE", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/Task.java" + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2052051397": { - "message": "Clear animatingExit: reason=destroySurface win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" + "-1298801500610545721": { + "message": "Cleaning splash screen token=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2049725903": { - "message": "Task back pressed on root taskId=%d", + "-1948849214526113495": { + "message": "Clearing startingData for token=%s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2039580386": { - "message": "Attempted to add input method window with unknown token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "5545923784327902026": { + "message": "Schedule remove starting %s startingWindow=%s animate=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2036671725": { - "message": " SKIP: is wallpaper", + "-5150982660941074218": { + "message": "startingWindow was set but startingSurface==null, couldn't remove", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2024464438": { - "message": "app-onAnimationFinished(): mOuter=%s", + "-2178757341169633804": { + "message": "Tried to remove starting window but startingWindow was null: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "5521236266092347335": { + "message": "reparent: moving activity=%s to new task fragment in task=%d at %d", + "level": "INFO", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "-9024836052864189016": { + "message": "moveFocusableActivityToTop: unfocusable activity=%s", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2014162875": { - "message": "Could not register window container listener token=%s, container=%s", - "level": "ERROR", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowContextListenerController.java" + "134255351804410010": { + "message": "moveFocusableActivityToTop: already on top and focused, activity=%s", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2012562539": { - "message": "startAnimation(): Notify animation start:", + "-1058622321669556178": { + "message": "moveFocusableActivityToTop: set focused, activity=%s", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-2010331310": { - "message": "resumeTopActivity: Top activity resumed (dontWaitForPause) %s", + "731006689098152100": { + "message": "moveFocusableActivityToTop: activity=%s", "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "3707721620395081349": { + "message": "Finishing activity r=%s, result=%d, data=%s, reason=%s", + "level": "VERBOSE", "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1980468143": { - "message": "DisplayArea appeared name=%s", + "-3691592300155948194": { + "message": "Finish needs to pause: %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1979455254": { - "message": "Launch on display check: allow launch for caller present on the display", + "5813636479397543744": { + "message": "Finish waiting for pause of: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "-2989211291975863399": { + "message": "destroyIfPossible: r=%s destroy returned removed=%s", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + "group": "WM_DEBUG_CONTAINERS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1976930686": { - "message": "Attempted to add Accessibility overlay window with bad token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "3169053633576517098": { + "message": "Enqueueing pending finish: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1973119651": { - "message": "SyncGroup %d: Adding to group: %s", + "9050478058743283018": { + "message": "activity %s already destroying, skipping request with reason:%s", "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1969928125": { - "message": "Animation start for %s, anim=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/SurfaceAnimator.java" + "5672598223877126839": { + "message": "Moving to DESTROYING: %s (destroy requested)", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1963461591": { - "message": "Removing %s from %s", + "-1834399855266808961": { + "message": "Moving to DESTROYED: %s (destroy skipped)", "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "3282063745558462269": { + "message": "Moving to DESTROYED: %s (no app)", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "8836546031252812807": { + "message": "Removing activity %s, reason= %s callers=%s", + "level": "INFO", "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1963363332": { - "message": "Restart top activity process of Task taskId=%d", + "8348126473928520781": { + "message": "Moving to DESTROYED: %s (removed from history)", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1961637874": { - "message": "DeferredDisplayUpdater: applying DisplayInfo immediately", + "-8001673213497887656": { + "message": "activityDestroyedLocked: r=%s", "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java" + "group": "WM_DEBUG_CONTAINERS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1949279037": { - "message": "Attempted to add input method window with bad token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "587363723665813898": { + "message": "Removing activity %s hasSavedState=%b stateNotNeeded=%s finishing=%b state=%s callers=%s", + "level": "INFO", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1939861963": { - "message": "Create root task displayId=%d winMode=%d", + "-1842512343787359105": { + "message": "Removing app token: %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1938839202": { - "message": "SURFACE LEAK DESTROY: %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "5548174277852675449": { + "message": "Removing app %s delayed=%b animation=%s animating=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "-601582700132879947": { + "message": "removeAppToken: %s delayed=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "3478214322581157355": { + "message": "removeAppToken make exiting: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1938204785": { + "-7226216420432530281": { + "message": "Removing focused app token:%s displayId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "8361394136152947990": { "message": "Moving existing starting %s from %s to %s", "level": "VERBOSE", "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1933723759": { - "message": "Clear animatingExit: reason=relayoutVisibleWindow win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" + "-3450064502566932331": { + "message": "Removing starting %s from %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1924376693": { - "message": " Setting Ready-group to %b. group=%s from %s", + "8639603536400037285": { + "message": "Moving pending starting from %s to %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1918702467": { - "message": "onSyncFinishedDrawing %s", + "-3452055378690362514": { + "message": "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s", "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/WindowContainer.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1915280162": { - "message": "Attempted to add wallpaper window with bad token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "1728033820691545386": { + "message": "No longer Stopped: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1906387645": { - "message": "SURFACE controller=%s alpha=%f HScale=%f, VScale=%f: %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + "5062176994575790703": { + "message": "TRANSIT_FLAG_OPEN_BEHIND, adding %s to mOpeningApps", + "level": "DEBUG", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1905191109": { - "message": "SyncGroup %d: Finished!", + "-477271988506706928": { + "message": "commitVisibility: %s: visible=%b visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s", "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1895337367": { - "message": "Delete root task display=%d winMode=%d", + "-6873410057142191118": { + "message": "State movement: %s from:%s to:%s reason:%s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1886145147": { - "message": "resumeTopActivity: Going to sleep and all paused", - "level": "DEBUG", + "4437231720834282527": { + "message": "State unchanged from:%s", + "level": "VERBOSE", "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1885450608": { - "message": "Content Recording: Successfully created a ContentRecordingSession for displayId=%d to mirror content from displayId=%d", + "926038819327785799": { + "message": "notifyAppResumed: wasStopped=%b %s", "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1884933373": { - "message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", + "1734586111478674085": { + "message": "Resumed activity; dropping state of: %s", "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1872288685": { - "message": "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1868518158": { - "message": "Pending back animation due to another animation is running", - "level": "WARN", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" + "-69666241054231397": { + "message": "Refreshed activity: %s", + "level": "INFO", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1868124841": { - "message": "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, orientationSensorEnabled=%b, keyguardDrawComplete=%b, windowManagerDrawComplete=%b", + "1256300416726217367": { + "message": "Activity paused: token=%s, timeout=%b", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1868048288": { - "message": "Updating to new configuration after starting activity.", + "6879640870754727133": { + "message": "Moving to PAUSED: %s %s", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityStarter.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1862269827": { - "message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s", + "2737811012914917932": { + "message": "Executing finish of failed to pause activity: %s", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1844540996": { - "message": " Initial targets: %s", + "-2566496855129705006": { + "message": "Waiting for pause to complete...", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1838803135": { - "message": "Attempted to set windowing mode to a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "7498807658620137882": { + "message": "no-history finish of %s", + "level": "DEBUG", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1834214907": { - "message": "createNonAppWindowAnimations()", + "3207149655622038378": { + "message": "Not finishing noHistory %s on stop because we're just sleeping", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1828118576": { - "message": "SyncGroup %d: Started %sfor listener: %s", + "-2530718588485487045": { + "message": "Moving to STOPPING: %s (stop requested)", "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1824578273": { - "message": "Reporting new frame to %s: %s", + "-8424334454318351870": { + "message": "Stop failed; moving to STOPPED: %s", "level": "VERBOSE", - "group": "WM_DEBUG_RESIZE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "-1818910559": { - "message": "DeferredDisplayUpdater: applied DisplayInfo after deferring", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1814361639": { - "message": "Set IME snapshot position: (%d, %d)", + "-4913512058893421188": { + "message": "Saving icicle of %s: %s", "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1812743677": { - "message": "Display id=%d is ignoring all orientation requests, camera is active and the top activity is eligible for force rotation, return %s,portrait activity: %b, is natural orientation portrait: %b.", + "7613353074402340933": { + "message": "Moving to STOPPED: %s (stop complete)", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1810446914": { - "message": "Trying to update display configuration for system\/invalid process.", - "level": "WARN", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "3981777934616509782": { + "message": "Scheduling idle now: forceIdle=%b immediate=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1800899273": { - "message": "applyAnimation: anim=%s transit=%s Callers=%s", + "1083992181663415298": { + "message": "Skipping set freeze of %s", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1792633344": { - "message": "Register task organizer=%s uid=%d", + "3713860954819212080": { + "message": "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, + "7696002120820208745": { + "message": "Clear freezing of %s force=%b", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1791031393": { - "message": "Ensuring correct configuration: %s", + "-8387262166329116492": { + "message": "No longer freezing: %s", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", + "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1782453012": { - "message": "Checking theme of starting window: 0x%x", + "-6965298896142649709": { + "message": "Finish starting %s: first real window is shown, no animation", "level": "VERBOSE", "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1777196134": { - "message": "goodToGo(): No apps to animate, mPendingAnimations=%d", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "3235691043029201724": { + "message": "Setting mOrientationChangeComplete=true because wtoken %s numInteresting=%d numDrawn=%d", + "level": "INFO", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1777010776": { - "message": "create IME snapshot for %s, buff width=%s, height=%s", + "5991628884266137609": { + "message": "Creating animation bounds layer", "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1768557332": { - "message": "removeWallpaperAnimation()", + "-1836789237982086339": { + "message": "No thumbnail header bitmap for: %s", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1764792832": { - "message": "Start collecting in Transition: %s", + "-8809523216004991008": { + "message": "Animation done in %s: reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "-1750206390": { - "message": "Exception thrown when creating surface for client %s (%s). %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1747461042": { - "message": "set mOrientationChanging of %s", + "-9178011226407552682": { + "message": "Setting requested orientation %s for %s", "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowState.java" + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1740512980": { - "message": "Stopping %s: nowVisible=%b animating=%b finishing=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + "-1963190756391505590": { + "message": "Sandbox max bounds for uid %s to bounds %s. config to never sandbox = %s, config to always sandbox = %s, letterboxing from mismatch with parent bounds = %s, has mCompatDisplayInsets = %s, should create compatDisplayInsets = %s", + "level": "DEBUG", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1730156332": { - "message": "Display id=%d rotation changed to %d from %d, lastOrientation=%d", + "2612201759169917322": { + "message": "Pausing configuration dispatch for %s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1728919185": { - "message": " unrelated invisible sibling %s", + "5153784493059555057": { + "message": "Resuming configuration dispatch for %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1710206702": { - "message": "Display id=%d is frozen while keyguard locked, return %d", + "-8630021188868292872": { + "message": "Skipping config check (will change): %s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1707370822": { - "message": "Ready to stop: %s", + "-3976984054291875926": { + "message": "Configuration doesn't matter in finishing %s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" - }, - "-1704402370": { - "message": "resetTaskIntendedTask: calling finishActivity on %s", - "level": "WARN", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1700778361": { - "message": "Content Recording: Going ahead with updating recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s", + "-1036762753077003128": { + "message": "Skipping config check in destroyed state %s", "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "-1699018375": { - "message": "Adding activity %s to task %s callers: %s", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/Task.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1679411993": { - "message": "setVr2dDisplayId called for: %d", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "-6543078196636665108": { + "message": "Skipping config check invisible: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1671601441": { - "message": "attachWindowContextToDisplayContent: calling from non-existing process pid=%d uid=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-3588725633248053181": { + "message": "Ensuring correct configuration: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1670695197": { - "message": "Attempted to add presentation window to a non-suitable display. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "4672360193194734037": { + "message": "Configuration & display unchanged in %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1647332198": { - "message": "remove RecentTask %s when finishing user %d", - "level": "INFO", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RecentTasks.java" + "-8624278141553396410": { + "message": "Skipping config check for initializing activity: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1643780158": { - "message": "Saving original orientation before camera compat, last orientation is %d", + "2485365009287691179": { + "message": "Configuration no differences in %s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1639406696": { - "message": "NOSENSOR override detected", + "-8909639363543223474": { + "message": "Configuration changes for %s, allChanges=%s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1638958146": { - "message": "Removing activity %s from task=%s adding to task=%s Callers=%s", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" + "-8048404379899908050": { + "message": "Configuration doesn't matter not running %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1633115609": { - "message": "Key dispatch not paused for screen off", + "4979286847769557939": { + "message": "Checking to restart %s: changed=0x%s, handles=0x%s, mLastReportedConfiguration=%s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1632122349": { - "message": "Changing surface while display frozen: %s", + "6779426581354721909": { + "message": "Config is relaunching %s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1631991057": { - "message": "Display id=%d is notified that Camera %s is closed but activity is still refreshing. Rescheduling an update.", + "8969401915706456725": { + "message": "Config is relaunching invisible activity %s called by %s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1630752478": { - "message": "removeLockedTask: removed %s", - "level": "DEBUG", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" + "328802837600679598": { + "message": "Moving to %s Relaunching %s callers=%s", + "level": "INFO", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1598452494": { - "message": "activityDestroyedLocked: r=%s", + "-3997125892953197985": { + "message": "Resumed after relaunch %s", "level": "DEBUG", - "group": "WM_DEBUG_CONTAINERS", + "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1596995693": { - "message": "startAnimation", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "1665699123574159131": { + "message": "Starting activity when config will change = %b", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityStarter.java" }, - "-1585311008": { + "4748139468532105082": { + "message": "Updating to new configuration after starting activity.", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityStarter.java" + }, + "-2867366986304729": { "message": "Bring to front target: %s from %s", "level": "DEBUG", "group": "WM_DEBUG_TASKS", "at": "com\/android\/server\/wm\/ActivityStarter.java" }, - "-1583619037": { - "message": "Failed to register MediaProjectionWatcherCallback", - "level": "ERROR", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/ScreenRecordingCallbackController.java" + "-2190454940975874759": { + "message": "Starting new activity %s in new task %s", + "level": "VERBOSE", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityStarter.java" }, - "-1582845629": { - "message": "Starting animation on %s", + "5445799252721678675": { + "message": "Initial config: %s", "level": "VERBOSE", - "group": "WM_DEBUG_DIMMER", - "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1575977269": { - "message": "Skipping %s: mismatch root %s", + "-3811526397232923712": { + "message": "Cannot launch dream activity due to invalid state. dream component: %s packageName: %s", + "level": "ERROR", + "group": "WM_DEBUG_DREAM", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, + "-6981899770129924827": { + "message": "Dream packageName does not match active dream. Package %s does not match %s", + "level": "ERROR", + "group": "WM_DEBUG_DREAM", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + }, + "6075150529915862250": { + "message": "Applying new update lock state '%s' for %s", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_IMMERSIVE", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1568331821": { - "message": "Enabling listeners", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "-4356952232698761083": { + "message": "setFocusedRootTask: taskId=%d", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1567866547": { - "message": "Collecting in transition %d: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "301842347780487555": { + "message": "setFocusedTask: taskId=%d touchedActivity=%s", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1564228464": { - "message": "App died while pausing: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "7095858131234795548": { + "message": "moveTaskToFront: moving taskId=%d", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1559645910": { - "message": "Looking for task of type=%s, taskAffinity=%s, intent=%s, info=%s, preferredTDA=%s", + "-4458288191054594222": { + "message": "Could not find task for id: %d", "level": "DEBUG", "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1558137010": { - "message": "Config is relaunching invisible activity %s called by %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-1136891560663761442": { + "message": "moveTaskToRootTask: moving task=%d to rootTaskId=%d toTop=%b", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1554521902": { - "message": "showInsets(ime) was requested by different window: %s ", + "6954122272402912822": { + "message": "startLockTaskMode: %s", "level": "WARN", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1545962566": { - "message": "View server did not start", + "-829638795650515884": { + "message": "Allowlisting %d:%s", "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1539974875": { - "message": "removeAppToken: %s delayed=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "893763316922465955": { + "message": "moveRootTaskToDisplay: moving taskId=%d to displayId=%d", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1526645239": { - "message": "Timeout waiting for drawn: undrawn=%s", + "8392804603924461448": { + "message": "%s: caller %d is using old GET_TASKS but privileged; allowing", "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1518132958": { - "message": "fractionRendered boundsOverSource=%f", - "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + "4303745325174700522": { + "message": "%s: caller %d does not hold REAL_GET_TASKS; limiting output", + "level": "WARN", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1517908912": { - "message": "requestScrollCapture: caught exception dispatching to window.token=%s", + "-559595900417262876": { + "message": "Allowing features %d:0x%s", "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1501564055": { - "message": "Organized TaskFragment is not ready= %s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "2008996027621913637": { + "message": "Updating global configuration to: %s", + "level": "INFO", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1499134947": { - "message": "Removing starting %s from %s", + "-6404059840638143757": { + "message": "Update process config of %s to new config %s", "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "-1497837552": { - "message": "onAnimationFinished(): mPendingAnimations=%d", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1495062622": { - "message": "Can't report activity moved to display - client not running, activityRecord=%s, displayId=%d", + "2959074735946674755": { + "message": "Trying to update display configuration for system\/invalid process.", "level": "WARN", - "group": "WM_DEBUG_SWITCH", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1492881555": { - "message": "Starting activity when config will change = %b", - "level": "VERBOSE", + "5668810920995272206": { + "message": "Trying to update display configuration for invalid process, pid=%d", + "level": "WARN", "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityStarter.java" + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1483435730": { - "message": "InsetsSource setWin %s for type %s", + "-1123414663662718691": { + "message": "setVr2dDisplayId called for: %d", "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" }, - "-1480918485": { - "message": "Refreshed activity: %s", - "level": "INFO", + "7803197981786977817": { + "message": "no-history finish of %s on new resume", + "level": "DEBUG", "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" }, - "-1480772131": { - "message": "No app or window is requesting an orientation, return %d for display id=%d", + "4094852138446437211": { + "message": "realStartActivityLocked: Skipping start of r=%s some activities pausing...", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" }, - "-1478175541": { - "message": "No longer animating wallpaper targets!", + "1045761390992110034": { + "message": "Moving to PAUSED: %s (starting in paused state)", "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + }, + "-8529426827020190143": { + "message": "Launch on display check: displayId=%d callingPid=%d callingUid=%d", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" }, - "-1474602871": { + "9147909968067116569": { + "message": "Launch on display check: no caller info, skip check", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + }, + "4781135167649953680": { + "message": "Launch on display check: allow launch any on display", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + }, + "7828411869729995271": { "message": "Launch on display check: disallow launch on virtual display for not-embedded activity.", "level": "DEBUG", "group": "WM_DEBUG_TASKS", "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" }, - "-1474292612": { - "message": "Could not find task for id: %d", + "-2215878620906309682": { + "message": "Launch on display check: disallow activity embedding without permission.", "level": "DEBUG", "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" }, - "-1471518109": { - "message": "Set animatingExit: reason=onAppVisibilityChanged win=%s", + "986565579776405555": { + "message": "Launch on display check: %s launch for userId=%d on displayId=%d", "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" }, - "-1468740466": { - "message": "Moving to PAUSED: %s (starting in paused state)", + "-2201418325681949201": { + "message": "Launch on display check: allow launch for owner of the display", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + }, + "-4258279435559028377": { + "message": "Launch on display check: allow launch for caller present on the display", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + }, + "1496536241884839051": { + "message": "Stopping %s: nowVisible=%b animating=%b finishing=%s", "level": "VERBOSE", "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" }, - "-1452274694": { - "message": " CAN PROMOTE: promoting to parent %s", + "5677125188685281770": { + "message": "Ready to stop: %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" }, - "-1449515133": { - "message": "Content Recording: stopping active projection for display %d", + "3604633008357193496": { + "message": "Waiting for top state to be released by %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + }, + "3997062844427155487": { + "message": "Top resumed state released %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + }, + "-4049608245387511746": { + "message": "applyAnimation: override requested, but it is prohibited by policy.", "level": "ERROR", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1443029505": { - "message": "SAFE MODE ENABLED (menu=%d s=%d dpad=%d trackball=%d)", - "level": "INFO", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-2133100418670643322": { + "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1442613680": { - "message": " Creating Ready-group for Transition %d with root=%s", + "6121116119545820299": { + "message": "applyAnimation: anim=%s transit=%s Callers=%s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1438175584": { - "message": "Input focus has changed to %s display=%d", + "-8382864384468306610": { + "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s isEntrance=%b Callers=%s", "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/InputMonitor.java" + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1434147454": { - "message": "cleanupAnimation(): Notify animation finished mPendingAnimations=%d reorderMode=%d", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + "222576013987954454": { + "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE transit=%s Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1432963966": { - "message": "Moving to DESTROYING: %s (destroy requested)", + "4808089291562562413": { + "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL transit=%s Callers=%s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1427184084": { - "message": "addWindow: New client %s: window=%s Callers=%s", + "-1463563572526433695": { + "message": "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s isEntrance=%s Callers=%s", "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1421296808": { - "message": "Moving to RESUMED: %s (in existing)", + "-8749850292010208926": { + "message": "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b Callers=%s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1419762046": { - "message": "moveRootTaskToDisplay: moving taskId=%d to displayId=%d", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "5939232373291430513": { + "message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1419461256": { - "message": "resumeTopActivity: Resumed %s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "9082776604722675018": { + "message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1413901262": { - "message": "startRecentsActivity(): intent=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" + "-1218632020771063497": { + "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b canCustomizeAppTransition=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1410260105": { - "message": "Schedule IME show for %s", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + "6217525691846442213": { + "message": "Override pending remote transitionSet=%b adapter=%s", + "level": "INFO", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1397175017": { - "message": "Other orientation overrides are in place: not reverting", + "5233255302148535928": { + "message": "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b mOpeningApps.size()=%d mClosingApps.size()=%d mChangingApps.size()=%d", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransition.java" }, - "-1394745488": { - "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s", - "level": "INFO", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" + "-5726018006883159788": { + "message": "Delaying app transition for recents animation to finish", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1391944764": { - "message": "SURFACE DESTROY: %s. %s", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + "6514556033257323299": { + "message": "**** GOOD TO GO", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1389772804": { - "message": "Attempted to add voice interaction window with bad token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "3518082157667760495": { + "message": "handleAppTransitionReady: displayId=%d appTransition={%s} openingApps=[%s] closingApps=[%s] transit=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1383884640": { - "message": " allReady query: used=%b override=%b defer=%d states=[%s]", + "-2503124388387340567": { + "message": "Wallpaper animation!", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1376035390": { - "message": "No task found", + "855146509305002043": { + "message": "We don't support remote animation for Task with multiple TaskFragmentOrganizers.", + "level": "ERROR", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "59396412370137517": { + "message": "Override with TaskFragment remote animation for transit=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "2280055488397326910": { + "message": "Task=%d contains embedded TaskFragment. Disabled all input during TaskFragment remote animation.", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1364754753": { - "message": "Task vanished taskId=%d", + "-3156084190956669377": { + "message": "Changing app %s visible=%b performLayout=%b", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1352076759": { - "message": "Removing app token: %s", + "-8226278785414579647": { + "message": "getAnimationTarget in=%s, out=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/AppTransitionController.java" + }, + "4418653408751596915": { + "message": "Now opening app %s", "level": "VERBOSE", "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1350198040": { - "message": "hideBootMessagesLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-8367738619313176909": { + "message": "Now closing app %s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1340540100": { - "message": "Creating SnapshotStartingData", + "1855459282905873641": { + "message": "Now changing app %s", "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1325565952": { - "message": "Attempted to get home support flag of a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "2951634988136738868": { + "message": "Checking %d opening apps (frozen=%b timeout=%b)...", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1323783276": { - "message": "performEnableScreen: bootFinished() failed.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "4963754906024950916": { + "message": "Delaying app transition for screen rotation animation to finish", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1318478129": { - "message": "applyAnimation: win=%s anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s", + "5073676463280304697": { + "message": "Check opening app=%s: allDrawn=%b startingDisplayed=%b startingMoved=%b isRelaunching()=%b startingWindow=%s", "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1311436264": { - "message": "Unregister task fragment organizer=%s uid=%d pid=%d", + "3437142041296647115": { + "message": "isFetchingAppTransitionSpecs=true", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1305966693": { - "message": "Sending position change to %s, onTop: %b", + "1461079689316480707": { + "message": "unknownApps is not empty: %s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1305791032": { - "message": "Moving to STOPPED: %s (stop complete)", + "3579533288018884842": { + "message": "Organized TaskFragment is not ready= %s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/AppTransitionController.java" }, - "-1305755880": { - "message": "Initial config: %s", + "495867940519492701": { + "message": "SyncGroup %d: onSurfacePlacement checking %s", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" }, - "-1304806505": { - "message": "Starting new activity %s in new task %s", + "8452501904614439940": { + "message": "SyncGroup %d: Unfinished dependencies: %s", "level": "VERBOSE", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityStarter.java" + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" }, - "-1303628829": { - "message": "**** STARTING EXIT", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/DisplayPolicy.java" + "616739530932040800": { + "message": "SyncGroup %d: Unfinished container: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" }, - "-1292329638": { - "message": "Added starting %s: startingWindow=%s startingView=%s", + "6649777898123506907": { + "message": "SyncGroup %d: Finished!", "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" }, - "-1288007399": { - "message": "performShowLocked: mDrawState=HAS_DRAWN in %s", + "4174320302463990554": { + "message": "PendingStartTransaction found", "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" }, - "-1277068810": { - "message": "startBackNavigation currentTask=%s, topRunningActivity=%s, callbackInfo=%s, currentFocus=%s", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" + "6310906192788668020": { + "message": "SyncGroup %d: Set ready %b", + "level": "VERBOSE", + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" }, - "-1263316010": { - "message": "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and oldRotation=%s (%d)", + "-476337038362199951": { + "message": "SyncGroup %d: Adding to group: %s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" }, - "-1259022216": { - "message": "SURFACE HIDE ( %s ): %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + "-2978812352001196863": { + "message": "SyncGroup %d: Started %sfor listener: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" }, - "-1258739769": { - "message": "onTransactionReady, opening: %s, closing: %s, animating: %s, match: %b", - "level": "DEBUG", + "-699215053676660941": { + "message": "No focused window, defaulting to top current task's window", + "level": "WARN", "group": "WM_DEBUG_BACK_PREVIEW", "at": "com\/android\/server\/wm\/BackNavigationController.java" }, - "-1257821162": { - "message": "OUT SURFACE %s: copied", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1256520588": { - "message": "performEnableScreen: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "-1253056469": { - "message": "Launch on display check: %s launch for userId=%d on displayId=%d", + "-1459414342866553129": { + "message": "Current focused window being animated by recents. Overriding back callback to recents controller callback.", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" }, - "-1248645819": { - "message": "\tAdd container=%s", + "2881085074175114605": { + "message": "Focused window didn't have a valid surface drawn.", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "-1243510456": { - "message": "Dim animation requested: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_DIMMER", - "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java" + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" }, - "-1237827119": { - "message": "Schedule remove starting %s startingWindow=%s animate=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-6183551796617134986": { + "message": "Focus window is closing.", + "level": "DEBUG", + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" }, - "-1228653755": { - "message": "Launch on display check: displayId=%d callingPid=%d callingUid=%d", + "4039315468791789889": { + "message": "startBackNavigation currentTask=%s, topRunningActivity=%s, callbackInfo=%s, currentFocus=%s", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" }, - "-1219773477": { - "message": "setInputConsumerEnabled(%s): mCanceled=%b", + "8456834061534378653": { + "message": "Previous Destination is Activity:%s Task:%s removedContainer:%s, backType=%s", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" }, - "-1217596375": { - "message": "Content Recording: Display %d has no content and is on, so start recording for state %d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "4900967164780429209": { + "message": "Pending back animation due to another animation is running", + "level": "WARN", + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" }, - "-1209762265": { - "message": "Registering listener=%s with id=%d for window=%s with %s", + "-6431452312492819825": { + "message": "onTransactionReady, opening: %s, closing: %s, animating: %s, match: %b", "level": "DEBUG", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" }, - "-1209252064": { - "message": "Clear animatingExit: reason=clearAnimatingFlags win=%s", + "-4051770154814262074": { + "message": "Handling the deferred animation after transition finished", "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" }, - "-1207757583": { - "message": "startAnimation(): Notify animation start: %s", + "2077221835543623088": { + "message": "Setting Activity.mLauncherTaskBehind to true. Activity=%s", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" }, - "-1204565480": { - "message": "Adding display switch to existing collecting transition", + "-4442170697458371588": { + "message": "Setting Activity.mLauncherTaskBehind to false. Activity=%s", "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/PhysicalDisplaySwitchTransitionLauncher.java" - }, - "-1198579104": { - "message": "Pushing next activity %s out to target's task %s", - "level": "VERBOSE", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" }, - "-1193946201": { - "message": "Can't report activity position update - client not running, activityRecord=%s", - "level": "WARN", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "267946503010201613": { + "message": "onBackNavigationDone backType=%s, triggerBack=%b", + "level": "DEBUG", + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/BackNavigationController.java" }, - "-1187377055": { - "message": "Enqueue pending stop if needed: %s wasStopping=%b visibleRequested=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "-2963535976860666511": { + "message": " BLACK %s: CREATE layer=%d", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/BlackFrame.java" }, - "-1185473319": { - "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s", + "-5633771912572750947": { + "message": " BLACK %s: DESTROY", "level": "INFO", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/BlackFrame.java" }, - "-1164930508": { - "message": "Moving to RESUMED: %s (starting new instance) callers=%s", + "-74949168947384056": { + "message": "Sending to proc %s new compat %s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/Task.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/CompatModePackages.java" }, - "-1156314529": { + "-6620483833570774987": { "message": "Content Recording: Unexpectedly null window container; unable to update recording for display %d", "level": "VERBOSE", "group": "WM_DEBUG_CONTENT_RECORDING", "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1156118957": { - "message": "Updated config=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "-1153814764": { - "message": "onAnimationCancelled", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java" - }, - "-1152771606": { + "7226080178642957768": { "message": "Content Recording: Display %d was already recording, but pause capture since the task is in PIP", "level": "VERBOSE", "group": "WM_DEBUG_CONTENT_RECORDING", "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1145384901": { - "message": "shouldWaitAnimatingExit: isTransition: %s", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowState.java" + "-311001578548807570": { + "message": "Content Recording: Display %d was already recording, so apply transformations if necessary", + "level": "VERBOSE", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1142279614": { - "message": "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s", + "2350883351096538149": { + "message": "Content Recording: Going ahead with updating recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s", "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1136734598": { - "message": "Content Recording: Ignoring session on same display %d, with an existing session %s", + "8446758574558556540": { + "message": "Content Recording: Unable to update recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s, since the surface is not available.", "level": "VERBOSE", "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecordingController.java" + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1136467585": { - "message": "The listener does not exist.", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowContextListenerController.java" + "-4320004054011530388": { + "message": "Content Recording: Display %d has content (%b) so pause recording", + "level": "VERBOSE", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1136139407": { - "message": "no-history finish of %s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "5951434375221687741": { + "message": "Content Recording: Stop MediaProjection on virtual display %d", + "level": "VERBOSE", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1130891072": { - "message": "Orientation continue waiting for draw in %s", + "-3395581813971405090": { + "message": "Content Recording: waiting to record, so do nothing", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1130868271": { - "message": "Resizing %s WITH DRAW PENDING", - "level": "INFO", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowState.java" + "6779858226066635065": { + "message": "Content Recording: Display %d should start recording, but don't yet since the task is in PIP", + "level": "VERBOSE", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1117599386": { - "message": "Deferring rotation, display is not enabled.", + "7051210836345306671": { + "message": "Content Recording: Unable to start recording for display %d since the surface is not available.", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1115019498": { - "message": "Configuration & display unchanged in %s", + "2255758299558330282": { + "message": "Content Recording: Display %d has no content and is on, so start recording for state %d", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1113134997": { - "message": "Attempted to add application window with unknown token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "2269158922723670768": { + "message": "Unable to retrieve window container to start recording for display %d", + "level": "VERBOSE", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1108775960": { - "message": "%s is requesting orientation %d (%s)", + "-2177493963028285555": { + "message": "Content Recording: Unable to start recording due to null token for display %d", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowContainer.java" + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1104347731": { - "message": "Setting requested orientation %s for %s", + "-928577038848872043": { + "message": "Content Recording: Unable to retrieve task to start recording for display %d", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1103716954": { - "message": "Not removing %s due to exit animation", + "-3564317873468917405": { + "message": "Content Recording: Unable to start recording due to invalid region for display %d", "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1103115659": { - "message": "Performing post-rotate rotation", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "1100676037289065396": { + "message": "Content Recording: Apply transformations of shift %d x %d, scale %f x %f, crop (aka recorded content size) %d x %d for display %d; display has size %d x %d; surface has size %d x %d", + "level": "VERBOSE", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1101551167": { - "message": "Auto-PIP allowed, entering PIP mode directly: %s, didAutoPip: %b", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "2330946591287751995": { + "message": "Content Recording: Provided surface for recording on display %d is not present, so do not update the surface", + "level": "VERBOSE", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1097851684": { - "message": "Content Recording: Unable to start recording due to null token for display %d", + "7993045936648632984": { + "message": "Content Recording: Recorded task is removed, so stop recording on display %d", "level": "VERBOSE", "group": "WM_DEBUG_CONTENT_RECORDING", "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1089874824": { - "message": "SURFACE SHOW (performLayout): %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + "3197882223327917085": { + "message": "Content Recording: stopping active projection for display %d", + "level": "ERROR", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1075136930": { - "message": "startLockTaskMode: Can't lock due to auth", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" + "4391984931064789228": { + "message": "Content Recording: Unable to tell MediaProjectionManagerService to stop the active projection for display %d: %s", + "level": "ERROR", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1069336896": { - "message": "onRootTaskOrderChanged(): rootTask=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" + "6721270269112237694": { + "message": "Content Recording: Unable to tell MediaProjectionManagerService about resizing the active projection: %s", + "level": "ERROR", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" }, - "-1060529098": { - "message": " Skipping post-transition snapshot for task %d", + "1600318776990120244": { + "message": "Content Recording: Unable to tell MediaProjectionManagerService about visibility change on the active projection: %s", + "level": "ERROR", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" + }, + "-1451477179301743956": { + "message": "Content Recording: Unable to tell log windowing mode change: %s", + "level": "ERROR", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecorder.java" + }, + "-225319884529912382": { + "message": "Content Recording: Accept session updating same display %d with granted consent, with an existing session %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecordingController.java" }, - "-1060365734": { - "message": "Attempted to add QS dialog window with bad token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-5981322449150461244": { + "message": "Content Recording: Ignoring session on same display %d, with an existing session %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecordingController.java" }, - "-1047945589": { - "message": "Remove client=%x, surfaceController=%s Callers=%s", + "4226710957373144819": { + "message": "Content Recording: Handle incoming session on display %d, with a pre-existing session %s", "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecordingController.java" }, - "-1043981272": { - "message": "Reverting orientation. Rotating to %s from %s rather than %s.", + "-1415855962859555663": { + "message": "Content Recording: Incoming session on display %d can't be set since it is already null; the corresponding VirtualDisplay must have already been removed.", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecordingController.java" }, - "-1042574499": { - "message": "Attempted to add Accessibility overlay window with unknown token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-5750232782380780139": { + "message": "Content Recording: Pause the recording session on display %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/ContentRecordingController.java" }, - "-1033630971": { - "message": "onBackNavigationDone backType=%s, triggerBack=%b", + "-8058211784911995417": { + "message": "DeferredDisplayUpdater: applying DisplayInfo immediately", "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java" }, - "-1028213464": { - "message": "%s skipping animation and directly setting alpha=%f, blur=%d", + "1944392458089872195": { + "message": "DeferredDisplayUpdater: partially applying DisplayInfo immediately", "level": "DEBUG", - "group": "WM_DEBUG_DIMMER", - "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java" }, - "-1022146708": { - "message": "Skipping %s: mismatch activity type", + "8391643185322408089": { + "message": "DeferredDisplayUpdater: deferring DisplayInfo update", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java" }, - "-1016578046": { - "message": "Moving to %s Relaunching %s callers=%s", - "level": "INFO", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-915675022936690176": { + "message": "DeferredDisplayUpdater: applied DisplayInfo after deferring", + "level": "DEBUG", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java" }, - "-1009117329": { - "message": "isFetchingAppTransitionSpecs=true", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "3778139410556664218": { + "message": "%s skipping animation and directly setting alpha=%f, blur=%d", + "level": "DEBUG", + "group": "WM_DEBUG_DIMMER", + "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java" }, - "-1005167552": { - "message": "Playing #%d in parallel on track #%d", + "-6357087772993832060": { + "message": "Starting animation on %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" + "group": "WM_DEBUG_DIMMER", + "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java" }, - "-1003678883": { - "message": "Cleaning splash screen token=%s", + "-1187783168730646350": { + "message": "Dim animation requested: %s", "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_DIMMER", + "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java" }, - "-1003060523": { - "message": "Finish needs to pause: %s", + "2230151187668089583": { + "message": "%s forcing orientation to %d for display id=%d", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayArea.java" }, - "-993378225": { - "message": "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s", + "3968604152682328317": { + "message": "Register display organizer=%s uid=%d", "level": "VERBOSE", - "group": "WM_DEBUG_DRAW", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" }, - "-986746907": { - "message": "Starting window removed %s", - "level": "DEBUG", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/WindowState.java" + "-3066370283926570943": { + "message": "Don't organize or trigger events for untrusted displayId=%d", + "level": "WARN", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" }, - "-962760979": { - "message": "thawRotation: mRotation=%d, caller=%s", + "-943497726140336963": { + "message": "Unregister display organizer=%s uid=%d", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" }, - "-961053385": { - "message": "attachWindowContextToDisplayArea: calling from non-existing process pid=%d uid=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "5147103403966149923": { + "message": "Create TaskDisplayArea uid=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" }, - "-957060823": { - "message": "Moving to PAUSING: %s", + "-1659480097203667175": { + "message": "Delete TaskDisplayArea uid=%d", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" }, - "-951939129": { - "message": "Unregister task organizer=%s uid=%d", + "-4514772405648277945": { + "message": "DisplayArea appeared name=%s", "level": "VERBOSE", "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" }, - "-948446688": { - "message": "Create TaskDisplayArea uid=%d", + "995846188225477231": { + "message": "DisplayArea vanished name=%s", "level": "VERBOSE", "group": "WM_DEBUG_WINDOW_ORGANIZER", "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" }, - "-938271693": { - "message": "allResumedActivitiesIdle: rootTask=%d %s not idle", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "-1007032390526684388": { + "message": "DisplayArea info changed name=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" }, - "-937498525": { - "message": "Executing finish of failed to pause activity: %s", + "4917824058925068521": { + "message": "The TaskDisplayArea with %s does not exist.", + "level": "WARN", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/DisplayAreaPolicyBuilder.java" + }, + "1432179297701477868": { + "message": "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-930893991": { - "message": "Set sync ready, syncId=%d", + "-1998969924927409574": { + "message": "findFocusedWindow: focusedApp=null using new focus @ %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/WindowOrganizerController.java" + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-929676529": { - "message": "Configuration changes for %s, allChanges=%s", + "-1513212297283619351": { + "message": "findFocusedWindow: focusedApp windows not focusable using new focus @ %s", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-927199900": { - "message": "Updating global configuration to: %s", - "level": "INFO", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "271075236829935631": { + "message": "findFocusedWindow: Reached focused app=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-926231510": { - "message": "State unchanged from:%s", + "3066566560703920191": { + "message": "findFocusedWindow: Found new focus @ %s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-921346089": { - "message": "Content Recording: Unable to tell MediaProjectionManagerService to stop the active projection for display %d: %s", - "level": "ERROR", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "-8667452489821572603": { + "message": "First draw done in potential wallpaper target %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WALLPAPER", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-917215012": { - "message": "%s: caller %d is using old GET_TASKS but privileged; allowing", - "level": "WARN", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "6283995720623600346": { + "message": "handleNotObscuredLocked: %s was holding screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by%s", + "level": "DEBUG", + "group": "WM_DEBUG_KEEP_SCREEN_ON", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-916108501": { - "message": "Adding %s to %s", + "1959209522588955826": { + "message": "Acquiring screen wakelock due to %s", + "level": "DEBUG", + "group": "WM_DEBUG_KEEP_SCREEN_ON", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "352937214222086717": { + "message": "Releasing screen wakelock, obscured by %s", + "level": "DEBUG", + "group": "WM_DEBUG_KEEP_SCREEN_ON", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "2632363530212357762": { + "message": "Set mOrientationChanging of %s", "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-914253865": { - "message": "Attempted to add voice interaction window with unknown token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-9191821315942566105": { + "message": "Display id=%d is frozen while keyguard locked, return %d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-894942237": { - "message": "Force Playing Transition: %d", + "-74384795669614579": { + "message": "Display id=%d is ignoring orientation request for %d, return %d following a per-app override for %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-888703350": { - "message": "Skipping %s", + "-3395592185328682328": { + "message": "Display id=%d is ignoring orientation request for %d, return %d", "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-883738232": { - "message": "Adding more than one toast window for UID at a time.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "3438870491084701232": { + "message": "No app or window is requesting an orientation, return %d for display id=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-877494781": { - "message": "Start pushing activity %s out to bottom task %s", + "-1123818872155982592": { + "message": "findFocusedWindow: No focusable windows, display=%d", "level": "VERBOSE", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-874888131": { - "message": "Set transition ready=%b %d", + "-2192125645150932161": { + "message": "Current transition prevents automatic focus change", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-874446906": { - "message": "showBootMessage: msg=%s always=%b mAllowBootMessages=%b mShowingBootMessages=%b mSystemBooted=%b. %s", + "3101160328044493048": { + "message": "Changing focus from %s to %s displayId=%d Callers=%s", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "7634130879993688940": { + "message": "setFocusedApp %s displayId=%d Callers=%s", "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-874087484": { - "message": "SyncGroup %d: Set ready %b", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" + "-4130402450005935184": { + "message": "SURFACE LEAK DESTROY: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-869242375": { - "message": "Content Recording: Unable to start recording due to invalid region for display %d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "4464269036743635127": { + "message": "setInputMethodTarget %s", + "level": "INFO", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-863438038": { - "message": "Aborting Transition: %d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "4835192778854186097": { + "message": "create IME snapshot for %s, buff width=%s, height=%s", + "level": "INFO", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-861859917": { - "message": "Attempted to add window to a display that does not exist: %d. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "2408509162360028352": { + "message": "Set IME snapshot position: (%d, %d)", + "level": "INFO", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-861707633": { - "message": "Destroying surface %s called by %s", + "2005731931732324688": { + "message": "remove IME snapshot, caller=%s", "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-856750101": { - "message": "Launch on display check: allow launch for owner of the display", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + "-6495118720675662641": { + "message": "show IME snapshot, ime target=%s, callers=%s", + "level": "INFO", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-856590985": { - "message": "dcTarget: %s mImeRequester: %s", - "level": "DEBUG", + "-4354595179162289537": { + "message": "setInputMethodInputTarget %s", + "level": "INFO", "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-853404763": { - "message": "\twallpaper=%s", + "2432701541536053712": { + "message": "DisplayContent: boot is waiting for window of type %d to be drawn", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-853226675": { - "message": "Attempted to add window with exiting application token .%s Aborting.", + "5683557566110711213": { + "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b", + "level": "INFO", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "-124113386733162358": { + "message": "onWindowAnimationFinished, wc=%s, type=%s, imeSnapshot=%s, target=%s", + "level": "INFO", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "-1556099709547629010": { + "message": "ImeContainer just became organized. Reparenting under parent. imeParentSurfaceControl=%s", + "level": "INFO", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "1119786654111970652": { + "message": "ImeContainer just became organized but it doesn't have a parent or the parent doesn't have a surface control. mSurfaceControl=%s imeParentSurfaceControl=%s", + "level": "ERROR", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "7019634211809476510": { + "message": "Execute app transition: %s, displayId: %d Callers=%s", "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-846931068": { - "message": "Update camera compat control state to %s for taskId=%d", + "-3219913508985161450": { + "message": "Wallpaper layer changed: assigning layers + relayout", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + "group": "WM_DEBUG_WALLPAPER", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-846078709": { - "message": "Configuration doesn't matter in finishing %s", + "-8165317816061445169": { + "message": "Content Recording: Display %d state was (%d), is now (%d), so update recording?", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-814760297": { - "message": "Looking for task of %s in %s", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "4162342172327950908": { + "message": "Content Recording: Attempting to mirror self on %d", + "level": "WARN", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-809771899": { - "message": "findFocusedWindow: Reached focused app=%s", + "5489691866309868814": { + "message": "Content Recording: Found no matching mirror display for id=%d for DEFAULT_DISPLAY. Nothing to mirror.", + "level": "WARN", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "-39794010824230928": { + "message": "Content Recording: Attempting to mirror %d from %d but no DisplayContent associated. Changing to mirror default display.", + "level": "WARN", + "group": "WM_DEBUG_CONTENT_RECORDING", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, + "6545352723229848841": { + "message": "Content Recording: Successfully created a ContentRecordingSession for displayId=%d to mirror content from displayId=%d", "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", + "group": "WM_DEBUG_CONTENT_RECORDING", "at": "com\/android\/server\/wm\/DisplayContent.java" }, - "-804217032": { - "message": "Skipping config check (will change): %s", + "-6228339285356824882": { + "message": "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, mScreenOnFully=%b, mKeyguardDrawComplete=%b, mWindowManagerDrawComplete=%b", + "level": "DEBUG", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/DisplayPolicy.java" + }, + "-6028033043540330282": { + "message": "Finished screen turning on...", + "level": "INFO", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/DisplayPolicy.java" + }, + "-7427596081878257508": { + "message": "selectAnimation in %s: transit=%d", + "level": "INFO", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/DisplayPolicy.java" + }, + "-6269658847003264525": { + "message": "**** STARTING EXIT", + "level": "INFO", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/DisplayPolicy.java" + }, + "-6776561147903919733": { + "message": "Deferring rotation, rotation is paused.", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-799396645": { - "message": "Display id=%d is notified that Camera %s is closed, updating rotation.", + "7439675997626642740": { + "message": "Deferring rotation, animation in progress.", "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-787664727": { - "message": "Cannot launch dream activity due to invalid state. dream component: %s packageName: %s", - "level": "ERROR", - "group": "WM_DEBUG_DREAM", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "1104181226551849840": { + "message": "Deferring rotation, still finishing previous rotation", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-784959154": { - "message": "Attempted to add private presentation window to a non-private display. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-2222079183499215612": { + "message": "Deferring rotation, display is not enabled.", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-783405930": { - "message": "Performing post-rotate rotation", - "level": "DEBUG", + "662988298513100908": { + "message": "Reverting orientation. Rotating to %s from %s rather than %s.", + "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-779535710": { - "message": "Transition %d: Set %s as transient-launch", + "-7113483678655694375": { + "message": "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and oldRotation=%s (%d)", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-779095785": { - "message": " sibling is a participant with mode %s", + "-8809129029906317617": { + "message": "Display id=%d selected orientation %s (%d), got rotation %s (%d)", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-778347463": { - "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mDisplayFrozen=%b callers=%s", + "6753221849083491323": { + "message": "Display id=%d rotation changed to %d from %d, lastOrientation=%d", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-775004869": { - "message": "Not a match: %s", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "-1216224951455892544": { + "message": "Performing post-rotate rotation after seamless rotation", + "level": "INFO", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-774908272": { - "message": "Marking #%d animation as SYNC.", + "-7672508047849737424": { + "message": "selectRotationAnimation topFullscreen=%s rotationAnimation=%d forceJumpcut=%b", + "level": "INFO", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "-2426404033822048710": { + "message": "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, orientationSensorEnabled=%b, keyguardDrawComplete=%b, windowManagerDrawComplete=%b", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-771177730": { - "message": "Removing focused app token:%s displayId=%d", + "7339471241580327852": { + "message": "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s", "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-767091913": { - "message": "Content Recording: Handle incoming session on display %d, with a pre-existing session %s", + "5325136615007859122": { + "message": "Invalid surface rotation angle in config_deviceTabletopRotations: %d", + "level": "ERROR", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "4616480353797749295": { + "message": "config_deviceTabletopRotations is not defined. Half-fold letterboxing will work inconsistently.", + "level": "WARN", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, + "8852346340572084230": { + "message": "foldStateChanged: displayId %d, halfFoldStateChanged %s, saved rotation: %d, mUserRotation: %d, mLastSensorRotation: %d, mLastOrientation: %d, mRotation: %d", "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecordingController.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-766059044": { - "message": "Display id=%d selected orientation %s (%d), got rotation %s (%d)", + "-8674269704471038429": { + "message": "onProposedRotationChanged, rotation=%d", "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-760801764": { - "message": "onAnimationCancelled", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" + "418312772547457152": { + "message": "Enabling listeners", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-760764543": { - "message": "Focus not requested for window=%s because it has no surface or is not focusable.", + "4641814558273780952": { + "message": "Disabling listeners", "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/InputMonitor.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" }, - "-754503024": { - "message": "Relayout %s: oldVis=%d newVis=%d. %s", - "level": "INFO", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "7429138692709430028": { + "message": "Display id=%d is ignoring all orientation requests, camera is active and the top activity is eligible for force rotation, return %s,portrait activity: %b, is natural orientation portrait: %b.", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" }, - "-743856570": { - "message": "shouldWaitAnimatingExit: isAnimating: %s", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowState.java" + "-7756685416834187936": { + "message": "Refreshing activity for camera compatibility treatment, activityRecord=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" }, - "-743431900": { - "message": "Configuration no differences in %s", + "-5176775281239247368": { + "message": "Reverting orientation after camera compat force rotation", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" }, - "-732715767": { - "message": "Unable to retrieve window container to start recording for display %d", + "-2188976047008497712": { + "message": "Saving original orientation before camera compat, last orientation is %d", "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" }, - "-729530161": { - "message": "Moving to DESTROYED: %s (no app)", + "-8302211458579221117": { + "message": "Display id=%d is notified that Camera %s is open for package %s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" }, - "-711194343": { - "message": "Setting Activity.mLauncherTaskBehind to false. Activity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" + "-1534784331886673955": { + "message": "DisplayRotationCompatPolicy: Multi-window toast not shown as package '%s' cannot be found.", + "level": "ERROR", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" }, - "-706481945": { - "message": "TaskFragment parent info changed name=%s parentTaskId=%d", + "1797195804376906831": { + "message": "Display id=%d is notified that Camera %s is closed, scheduling rotation update.", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" }, - "-705939410": { - "message": "Waiting for pause to complete...", + "-8746776274432739264": { + "message": "Display id=%d is notified that Camera %s is closed but activity is still refreshing. Rescheduling an update.", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" }, - "-703543418": { - "message": " check sibling %s", + "3622181214422515679": { + "message": "Display id=%d is notified that Camera %s is closed, updating rotation.", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" }, - "-702650156": { - "message": "Override with TaskFragment remote animation for transit=%s", + "-6949326633913532620": { + "message": "NOSENSOR override detected", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" }, - "-701167286": { - "message": "applyAnimation: transit=%s, enter=%b, wc=%s", + "-2060428960792625366": { + "message": "NOSENSOR override is absent: reverting", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" + }, + "-4296736202875980050": { + "message": "Other orientation overrides are in place: not reverting", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" }, - "-694710814": { + "7928129513685401229": { "message": "Pausing rotation during drag", "level": "DEBUG", "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DragState.java" }, - "-692907078": { - "message": "Handling the deferred animation after transition finished", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" - }, - "-677449371": { - "message": "moveTaskToRootTask: moving task=%d to rootTaskId=%d toTop=%b", + "8231481023986546563": { + "message": "Resuming rotation after drag", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "-672355406": { - "message": " Rejecting as no-op: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DragState.java" }, - "-668956537": { - "message": " THUMBNAIL %s: CREATE", + "12662399232325663": { + "message": "DRAG %s: pos=(%d,%d)", "level": "INFO", "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/SurfaceFreezer.java" + "at": "com\/android\/server\/wm\/DragState.java" }, - "-666510420": { - "message": "With display frozen, orientationChangeComplete=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "-1797662102094201628": { + "message": "Attempt to transfer touch gesture with non-existent embedded window", + "level": "WARN", + "group": "WM_DEBUG_EMBEDDED_WINDOWS", + "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" }, - "-658964693": { - "message": "onWindowAnimationFinished, wc=%s, type=%s, imeSnapshot=%s, target=%s", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "929964979835124721": { + "message": "Attempt to transfer touch gesture using embedded window with no associated host", + "level": "WARN", + "group": "WM_DEBUG_EMBEDDED_WINDOWS", + "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" }, - "-655104359": { - "message": "Frontmost changed immersion: %s", - "level": "DEBUG", - "group": "WM_DEBUG_IMMERSIVE", - "at": "com\/android\/server\/wm\/ActivityClientController.java" + "676191989331669410": { + "message": "Attempt to transfer touch gesture with host window not associated with embedded window", + "level": "WARN", + "group": "WM_DEBUG_EMBEDDED_WINDOWS", + "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" }, - "-653156702": { - "message": "createAppAnimations()", + "553249487221306249": { + "message": "Attempt to transfer touch gesture using embedded window that has no input channel", + "level": "WARN", + "group": "WM_DEBUG_EMBEDDED_WINDOWS", + "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" + }, + "-8678904073078032058": { + "message": "Attempt to transfer touch gesture using a host window with no input channel", + "level": "WARN", + "group": "WM_DEBUG_EMBEDDED_WINDOWS", + "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" + }, + "-786355099910065121": { + "message": "IME target changed within ActivityRecord", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" }, - "-648891906": { - "message": "Activity not running or entered PiP, resuming next.", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "2634707843050913730": { + "message": "Schedule IME show for %s", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" }, - "-641258376": { - "message": "realStartActivityLocked: Skipping start of r=%s some activities pausing...", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + "8923821958256605927": { + "message": "Run showImeRunner", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" }, - "-639217716": { - "message": "setFocusedApp %s displayId=%d Callers=%s", + "-3529253275087521638": { + "message": "call showInsets(ime) on %s", "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" }, - "-637815408": { - "message": "Invalid surface rotation angle in config_deviceTabletopRotations: %d", - "level": "ERROR", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "7927729210300708186": { + "message": "showInsets(ime) was requested by different window: %s ", + "level": "WARN", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" }, - "-636553602": { - "message": "commitVisibility: %s: visible=%b visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-6529782994356455131": { + "message": "abortShowImePostLayout", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" }, - "-635082269": { - "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b", - "level": "INFO", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "-6629998049460863403": { + "message": "dcTarget: %s mImeRequester: %s", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" }, - "-627759820": { - "message": "Display id=%d is notified that Camera %s is open for package %s", + "-8553129529717081823": { + "message": "Input focus has changed to %s display=%d", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/InputMonitor.java" }, - "-622997754": { - "message": "postWindowRemoveCleanupLocked: %s", + "4027486077547983902": { + "message": "App %s is focused, but the window is not ready. Start a transaction to remove focus from the window of non-focused apps.", "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/InputMonitor.java" }, - "-622017164": { - "message": "Finish Transition: %s", + "-8537908614386667236": { + "message": "Focus not requested for window=%s because it has no surface or is not focusable.", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/InputMonitor.java" }, - "-597091183": { - "message": "Delete TaskDisplayArea uid=%d", + "-6346673514571615151": { + "message": "Focus requested for window=%s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/InputMonitor.java" }, - "-593535526": { - "message": "Binding proc %s with config %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/am\/ActivityManagerService.java" + "1522894362518893789": { + "message": "InsetsSource setWin %s for type %s", + "level": "DEBUG", + "group": "WM_DEBUG_WINDOW_INSETS", + "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" }, - "-584061725": { - "message": "Content Recording: Accept session updating same display %d with granted consent, with an existing session %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecordingController.java" + "6243049416211184258": { + "message": "InsetsSource Control %s for target %s", + "level": "DEBUG", + "group": "WM_DEBUG_WINDOW_INSETS", + "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" }, - "-583031528": { - "message": "%s", + "-8234068212532234206": { + "message": "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s", + "level": "DEBUG", + "group": "WM_DEBUG_WINDOW_INSETS", + "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" + }, + "-8601070090234611338": { + "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s", "level": "INFO", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_WINDOW_INSETS", + "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" }, - "-576070986": { - "message": "Performing post-rotate rotation after seamless rotation", + "-6857870589074001153": { + "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s", "level": "INFO", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "group": "WM_DEBUG_WINDOW_INSETS", + "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" }, - "-567946587": { - "message": "Requested redraw for orientation change: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowState.java" + "-6684172224226118673": { + "message": "onImeControlTargetChanged %s", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/InsetsStateController.java" }, - "-561092364": { - "message": "onPointerDownOutsideFocusLocked called on %s", + "8891808212671675155": { + "message": "clearLockedTasks: %s", "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" }, - "-549028919": { - "message": "enableScreenIfNeededLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "8970634498594714645": { + "message": "removeLockedTask: removed %s", + "level": "DEBUG", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" }, - "-548282316": { - "message": "setLockTaskMode: Locking to %s Callers=%s", + "8735562128135241598": { + "message": "removeLockedTask: task=%s last task, reverting locktask mode. Callers=%s", + "level": "DEBUG", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" + }, + "737192738184050156": { + "message": "startLockTaskMode: Can't lock due to auth", "level": "WARN", "group": "WM_DEBUG_LOCKTASK", "at": "com\/android\/server\/wm\/LockTaskController.java" }, - "-547111355": { - "message": "hideIme Control target: %s ", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-7119521978513736788": { + "message": "Mode default, asking user", + "level": "WARN", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" }, - "-545190927": { - "message": "<<< CLOSE TRANSACTION animate", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowAnimator.java" + "-1557441750657584614": { + "message": "%s", + "level": "WARN", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" }, - "-542756093": { - "message": "TaskFragment vanished name=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + "-4314079913933391851": { + "message": "setLockTaskMode: Can't lock due to auth", + "level": "WARN", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" }, - "-532081937": { - "message": " Commit activity becoming invisible: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "3321878763832425380": { + "message": "setLockTaskMode: Locking to %s Callers=%s", + "level": "WARN", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" }, - "-529187878": { - "message": "Reverting orientation after camera compat force rotation", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + "-4819015209006579825": { + "message": "onLockTaskPackagesUpdated: removing %s mLockTaskAuth()=%s", + "level": "DEBUG", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" }, - "-521613870": { - "message": "App died during pause, not stopping: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "2119751067469297845": { + "message": "onLockTaskPackagesUpdated: starting new locktask task=%s", + "level": "DEBUG", + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/LockTaskController.java" }, - "-519504830": { - "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s isEntrance=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" + "3788905348567806832": { + "message": "startAnimation", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java" }, - "-517666355": { - "message": "Content Recording: Display %d has content (%b) so pause recording", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "705955074330737483": { + "message": "onAnimationCancelled", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java" }, - "-509601642": { - "message": " checking %s", - "level": "VERBOSE", + "5106303602270682056": { + "message": "Adding display switch to existing collecting transition", + "level": "DEBUG", "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "-507657818": { - "message": "Window %s is already added", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "at": "com\/android\/server\/wm\/PhysicalDisplaySwitchTransitionLauncher.java" }, - "-503656156": { - "message": "Update process config of %s to new config %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "3308140128142966415": { + "message": "remove RecentTask %s when finishing user %d", + "level": "INFO", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RecentTasks.java" }, - "-497620140": { - "message": "Transaction ready, syncId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/WindowOrganizerController.java" + "-3758280623533049031": { + "message": "Preload recents with %s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, - "-496681057": { - "message": "Attempted to get remove mode of a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-3365656764099317101": { + "message": "Updated config=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, - "-484194149": { - "message": "no-history finish of %s on new resume", + "-7165162073742035900": { + "message": "Real start recents", "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, - "-483957611": { - "message": "Resuming configuration dispatch for %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-3403665718306852375": { + "message": "startRecentsActivity(): intent=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, - "-481924678": { - "message": "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w.isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d", + "-8325607672707336373": { + "message": "No root task above target root task=%s", "level": "DEBUG", - "group": "WM_DEBUG_KEEP_SCREEN_ON", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, - "-479665533": { - "message": "DisplayRotationCompatPolicy: Multi-window toast not shown as package '%s' cannot be found.", - "level": "ERROR", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + "-7278356485797757819": { + "message": "Moved rootTask=%s behind rootTask=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, - "-464564167": { - "message": "Current transition prevents automatic focus change", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "1012359606301505741": { + "message": "Started intent=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, - "-463348344": { - "message": "Removing and adding activity %s to root task at top callers=%s", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/Task.java" + "5474198007669537235": { + "message": "onAnimationFinished(): controller=%s reorderMode=%d", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, - "-451552570": { - "message": "Current focused window being animated by recents. Overriding back callback to recents controller callback.", + "3525834288436624965": { + "message": "onAnimationFinished(): targetRootTask=%s targetActivity=%s mRestoreTargetBehindRootTask=%s", "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, - "-449118559": { - "message": "Trying to update display configuration for invalid process, pid=%d", + "-5961176083217302671": { + "message": "Expected target rootTask=%s to be top most but found rootTask=%s", "level": "WARN", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "-5893976429537642045": { + "message": "Expected target rootTask=%s to restored behind rootTask=%s but it is behind rootTask=%s", + "level": "WARN", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" }, - "-445944810": { + "4515487264815398694": { + "message": "onRootTaskOrderChanged(): rootTask=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimation.java" + }, + "6530904107141905844": { + "message": "screenshotTask(%d): mCanceled=%b", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "-3286551982713129633": { + "message": "setFinishTaskTransaction(%d): transaction=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + }, + "5187133389446459984": { "message": "finish(%b): mCanceled=%b", "level": "DEBUG", "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, - "-443173857": { - "message": "Moving pending starting from %s to %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "6879496555046975661": { + "message": "setInputConsumerEnabled(%s): mCanceled=%b", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, - "-439951996": { - "message": "Disabling listeners", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "-5305978958548091997": { + "message": "setHomeApp(%s)", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, - "-436553282": { - "message": "Remove sleep token: tag=%s, displayId=%d", + "-3801497203749932106": { + "message": "addAnimation(%s)", "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, - "-417730399": { - "message": "Preparing to sync a window that was already in the sync, so try dropping buffer. win=%s", + "3721473589747203697": { + "message": "removeAnimation(%d)", "level": "DEBUG", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, - "-415865166": { - "message": "findFocusedWindow: Found new focus @ %s", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "5156407755139006078": { + "message": "removeWallpaperAnimation()", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, - "-415346336": { - "message": "DeferredDisplayUpdater: partially applying DisplayInfo immediately", + "-1997836523186474317": { + "message": "startAnimation(): mPendingStart=%b mCanceled=%b", "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java" + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, - "-401282500": { - "message": "destroyIfPossible: r=%s destroy returned removed=%s", + "-7532294363367395195": { + "message": "startAnimation(): Notify animation start: %s", "level": "DEBUG", - "group": "WM_DEBUG_CONTAINERS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, - "-401029526": { - "message": "%s: caller %d does not hold REAL_GET_TASKS; limiting output", - "level": "WARN", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "-1336603089105439710": { + "message": "collectTaskRemoteAnimations, target: %s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, - "-399343789": { - "message": "Skipping %s: different user", + "2547528895718568379": { + "message": "createWallpaperAnimations()", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, - "-393505149": { - "message": "unable to update pointer icon", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "5444932814080651576": { + "message": "cancelAnimation(): reason=%s", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, - "-386552155": { - "message": "Attempted to set system decors flag to a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "622027757443954945": { + "message": "cleanupAnimation(): Notify animation finished mPendingAnimations=%d reorderMode=%d", + "level": "DEBUG", + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, - "-384639879": { - "message": "Acquiring screen wakelock due to %s", + "-5444412205083968021": { + "message": "createAnimationAdapter(): container=%s", "level": "DEBUG", - "group": "WM_DEBUG_KEEP_SCREEN_ON", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-381475323": { - "message": "DisplayContent: boot is waiting for window of type %d to be drawn", + "6986037643494242400": { + "message": "goodToGo()", "level": "DEBUG", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-379068494": { - "message": "unknownApps is not empty: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "-1902984034737899928": { + "message": "goodToGo(): Animation canceled already", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-376950429": { - "message": "DeferredDisplayUpdater: deferring DisplayInfo update", + "6727618365838540075": { + "message": "goodToGo(): No apps to animate, mPendingAnimations=%d", "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java" + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-374767836": { - "message": "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-2525509826755873433": { + "message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-373110070": { - "message": "Skipping task: (mismatch activity\/task) %s", + "-1148281153370899511": { + "message": "startAnimation(): Notify animation start:", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-360208282": { - "message": "Animating wallpapers: old: %s hidden=%b new: %s hidden=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" + "7501495587927045391": { + "message": "cancelAnimation(): reason=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-354571697": { - "message": "Existence Changed in transition %d: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "-1424368765415574722": { + "message": "Starting remote animation", + "level": "INFO", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-353495930": { - "message": "TaskFragmentTransaction changes are not collected in transition because there is an ongoing sync for applySyncTransaction().", - "level": "WARN", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowOrganizerController.java" + "-2676700429940607853": { + "message": "%s", + "level": "INFO", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-347866078": { - "message": "Setting move animation on %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" + "7094394833775573933": { + "message": "createAppAnimations()", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-344488673": { - "message": "Finishing drawing window %s: mDrawState=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + "-4411070227420990074": { + "message": "\tAdd container=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-322743468": { - "message": "setInputMethodInputTarget %s", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "-4411631520586057580": { + "message": "\tRemove container=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-322035974": { - "message": "App freeze timeout expired.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-7002230949892506736": { + "message": "createWallpaperAnimations()", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-319689203": { - "message": "Reparenting to original parent: %s for %s", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/SurfaceAnimator.java" + "8743612568733301175": { + "message": "createNonAppWindowAnimations()", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-317761482": { - "message": "Create sleep token: tag=%s, displayId=%d", + "-2716313493239418198": { + "message": "onAnimationFinished(): mPendingAnimations=%d", "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-317194205": { - "message": "clearLockedTasks: %s", - "level": "INFO", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" + "7221400292415257709": { + "message": "onAnimationFinished(): Notify animation finished:", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-315778658": { - "message": "transferTouchGesture failed because args transferFromToken or transferToToken is null", - "level": "ERROR", - "group": "WM_DEBUG_EMBEDDED_WINDOWS", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "7483194715776694698": { + "message": "\tcontainer=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-312353598": { - "message": "Executing finish of activity: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "6697982664439247822": { + "message": "\twallpaper=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-310337305": { - "message": "Activity config changed during resume: %s, new next: %s", + "6938838346517131964": { + "message": "\tnonApp=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + }, + "-3880290251819699866": { + "message": "Finishing remote animation", "level": "INFO", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-304728471": { - "message": "New wallpaper: target=%s prev=%s", + "-7169244688499657832": { + "message": "app-onAnimationFinished(): mOuter=%s", "level": "DEBUG", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-302468788": { - "message": "Expected target rootTask=%s to be top most but found rootTask=%s", - "level": "WARN", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" + "3923111589554171989": { + "message": "app-release(): mOuter=%s", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-292790591": { - "message": "Attempted to set IME policy to a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "8918152561092803537": { + "message": "startAnimation", + "level": "DEBUG", + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-275077723": { - "message": "New animation: %s old animation: %s", + "1736084564226683342": { + "message": "Starting remote display change: from [rot = %d], to [%dx%d, rot = %d]", "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java" }, - "-266707683": { - "message": "Moving #%d from collecting to waiting.", + "-4617490621756721600": { + "message": "resetTaskIntendedTask: calling finishActivity on %s", + "level": "WARN", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" + }, + "3361857745281957526": { + "message": "Removing activity %s from task=%s adding to task=%s Callers=%s", + "level": "INFO", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" + }, + "3958829063955690349": { + "message": "Pushing next activity %s out to target's task %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" }, - "-251259736": { - "message": "No longer freezing: %s", + "1730793580703791926": { + "message": "Start pushing activity %s out to bottom task %s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java" }, - "-248761393": { - "message": "startPausing: taskFrag =%s mResumedActivity=%s", + "-8961882615747561040": { + "message": "Looking for task of %s in %s", "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-240296576": { - "message": "handleAppTransitionReady: displayId=%d appTransition={%s} openingApps=[%s] closingApps=[%s] transit=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "8899721161806265460": { + "message": "Skipping task: (mismatch activity\/task) %s", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-235225312": { - "message": "Skipping config check for initializing activity: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "6841550641928224256": { + "message": "Skipping %s: voice session", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-233530384": { - "message": "Content Recording: Incoming session on display %d can't be set since it is already null; the corresponding VirtualDisplay must have already been removed.", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecordingController.java" + "4468520936943270392": { + "message": "Skipping %s: different user", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-230587670": { - "message": "SyncGroup %d: Unfinished container: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" + "-4764624740388751268": { + "message": "Skipping %s: mismatch root %s", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-228813488": { - "message": "%s: Setting back callback %s", + "9031436623838917667": { + "message": "Skipping %s: mismatch activity type", "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-208825711": { - "message": "shouldWaitAnimatingExit: isWallpaperTarget: %s", + "6022828946761399284": { + "message": "Comparing existing cls=%s \/aff=%s to new cls=%s \/aff=%s", "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-208664771": { - "message": "Reparenting to leash for %s", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/SurfaceAnimator.java" + "-3413620974545388702": { + "message": "Found matching class!", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-203358733": { - "message": "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + "-2649361982747625232": { + "message": "For Intent %s bringing to top: %s", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-198463978": { - "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "7046266138098744790": { + "message": "Found matching affinity candidate!", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-195654020": { - "message": "Attempt to transfer touch gesture with host window not associated with embedded window", - "level": "WARN", - "group": "WM_DEBUG_EMBEDDED_WINDOWS", - "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" + "6481733556290926693": { + "message": "Not a match: %s", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-193782861": { - "message": "Final remove of window: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_MOVEMENT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "3331249072840061049": { + "message": "New topFocusedDisplayId=%d", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-186693085": { - "message": "Starting a Recents transition which can be parallel.", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "865845626039449679": { + "message": "SURFACE RECOVER DESTROY: %s", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-182877285": { - "message": "Wallpaper layer changed: assigning layers + relayout", + "-4150611780753674023": { + "message": "Wallpaper may change! Adjusting", "level": "VERBOSE", "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-180594244": { - "message": "Content Recording: Unable to tell MediaProjectionManagerService about visibility change on the active projection: %s", - "level": "ERROR", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "4177291132772627699": { + "message": "With display frozen, orientationChangeComplete=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-177040661": { - "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s", + "-5513616928833586179": { + "message": "Performing post-rotate rotation", "level": "DEBUG", "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-172326720": { - "message": "Saving icicle of %s: %s", - "level": "INFO", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-7698723716637247994": { + "message": "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w.isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d", + "level": "DEBUG", + "group": "WM_DEBUG_KEEP_SCREEN_ON", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-168799453": { - "message": "Allowing features %d:0x%s", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "8621291657500572364": { + "message": "mUserActivityTimeout set to %d", + "level": "DEBUG", + "group": "WM_DEBUG_KEEP_SCREEN_ON", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-167822951": { - "message": "Attempted to add starting window to token with already existing starting window", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-1418592110950138870": { + "message": "Looking for task of type=%s, taskAffinity=%s, intent=%s, info=%s, preferredTDA=%s", + "level": "DEBUG", + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-163974242": { - "message": "setFinishTaskTransaction(%d): transaction=%s", + "2828976699481734755": { + "message": "No task found", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-143556958": { - "message": "resumeNextFocusableActivityWhenRootTaskIsEmpty: %s, go home", + "-4405347314716558580": { + "message": "Create sleep token: tag=%s, displayId=%d", "level": "DEBUG", "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/Task.java" - }, - "-125383273": { - "message": "Content Recording: waiting to record, so do nothing", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" - }, - "-124316973": { - "message": "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-116086365": { - "message": "******************** ENABLING SCREEN!", - "level": "INFO", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "1329131651776855609": { + "message": "Remove sleep token: tag=%s, displayId=%d", + "level": "DEBUG", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-108977760": { - "message": "Sandbox max bounds for uid %s to bounds %s. config to never sandbox = %s, config to always sandbox = %s, letterboxing from mismatch with parent bounds = %s, has mCompatDisplayInsets = %s, should create compatDisplayInsets = %s", + "1653728842643223887": { + "message": "allResumedActivitiesIdle: rootTask=%d %s not idle", "level": "DEBUG", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-106400104": { - "message": "Preload recents with %s", + "3785779399471740019": { + "message": "allPausedActivitiesComplete: r=%s state=%s", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/RootWindowContainer.java" }, - "-98422345": { - "message": "Focus window is closing.", + "4666728330189027178": { + "message": "Failed to register MediaProjectionWatcherCallback", + "level": "ERROR", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/ScreenRecordingCallbackController.java" + }, + "8010999385228654193": { + "message": " FREEZE %s: CREATE", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + }, + "-6586462455018013482": { + "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s", "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" }, - "-91393839": { - "message": "Set animatingExit: reason=remove\/applyAnimation win=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" + "-5825336546511998057": { + "message": " FREEZE %s: DESTROY", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" }, - "-87705714": { - "message": "findFocusedWindow: focusedApp=null using new focus @ %s", + "6883897856740637908": { + "message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s", "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + }, + "-3943622313307983155": { + "message": "ScreenRotationAnimation onAnimationEnd", + "level": "DEBUG", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + }, + "-1594708154257031561": { + "message": " NEW SURFACE SESSION %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/Session.java" }, - "-86763148": { + "2638961674625826260": { "message": " KILL SURFACE SESSION %s", "level": "INFO", "group": "WM_SHOW_TRANSACTIONS", "at": "com\/android\/server\/wm\/Session.java" }, - "-81260230": { - "message": "Display id=%d is notified that Camera %s is closed, scheduling rotation update.", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + "5380455212389185829": { + "message": "Removing dim surface %s on transaction %s", + "level": "DEBUG", + "group": "WM_DEBUG_DIMMER", + "at": "com\/android\/server\/wm\/SmoothDimmer.java" }, - "-81121442": { - "message": "ImeContainer just became organized but it doesn't have a parent or the parent doesn't have a surface control. mSurfaceControl=%s imeParentSurfaceControl=%s", - "level": "ERROR", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "-820649637734629482": { + "message": "Animation start delayed for %s", + "level": "INFO", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/SurfaceAnimator.java" }, - "-80004683": { - "message": "Resume failed; resetting state to %s: %s", + "1371702561758591499": { + "message": "Animation start for %s, anim=%s", + "level": "DEBUG", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/SurfaceAnimator.java" + }, + "-5370506662233296228": { + "message": "Cancelling animation restarting=%b for %s", + "level": "INFO", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/SurfaceAnimator.java" + }, + "-3045933321063743917": { + "message": "Reparenting to original parent: %s for %s", + "level": "INFO", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/SurfaceAnimator.java" + }, + "-855083149623806053": { + "message": "Reparenting to leash for %s", + "level": "INFO", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/SurfaceAnimator.java" + }, + "-2595923278763115975": { + "message": " THUMBNAIL %s: CREATE", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/SurfaceFreezer.java" + }, + "-8609432747982701423": { + "message": "Setting Intent of %s to %s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/Task.java" }, - "-70719599": { - "message": "Unregister remote animations for organizer=%s uid=%d pid=%d", + "-9155008290180285590": { + "message": "Setting Intent of %s to target %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + "group": "WM_DEBUG_TASKS", + "at": "com\/android\/server\/wm\/Task.java" }, - "-57750640": { - "message": "show IME snapshot, ime target=%s, callers=%s", + "6424220442758232673": { + "message": "Removing and adding activity %s to root task at top callers=%s", "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/Task.java" }, - "-57572004": { - "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b canCustomizeAppTransition=%b Callers=%s", + "-1028890010429408946": { + "message": "addChild: %s at top.", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/Task.java" }, - "-55185509": { - "message": "setFocusedTask: taskId=%d touchedActivity=%s", + "38991867929900764": { + "message": "setLockTaskAuth: task=%s mLockTaskAuth=%s", "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "group": "WM_DEBUG_LOCKTASK", + "at": "com\/android\/server\/wm\/Task.java" }, - "-50336993": { - "message": "moveFocusableActivityToTop: activity=%s", + "-3401780415681318335": { + "message": "applyAnimationUnchecked, control: %s, task: %s, transit: %s", "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_RECENTS_ANIMATIONS", + "at": "com\/android\/server\/wm\/Task.java" }, - "-33096143": { - "message": "applyAnimation: transition animation is disabled or skipped. container=%s", + "4446998544419008924": { + "message": "Moving to RESUMED: %s (starting new instance) callers=%s", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/Task.java" }, - "-32102932": { - "message": "Error sending initial configuration change to WindowContainer overlay", - "level": "ERROR", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" + "4037728373502324767": { + "message": "resumeNextFocusableActivityWhenRootTaskIsEmpty: %s, go home", + "level": "DEBUG", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/Task.java" }, - "-21399771": { - "message": "activity %s already destroying, skipping request with reason:%s", + "-2261257617975724313": { + "message": "Adding activity %s to task %s callers: %s", + "level": "INFO", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/Task.java" + }, + "7378236902389922467": { + "message": "App is requesting an orientation, return %d for display id=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/TaskDisplayArea.java" + }, + "2005499548343677845": { + "message": "No app is requesting an orientation, return %d for display id=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/TaskDisplayArea.java" + }, + "646076184396185067": { + "message": "App died while pausing: %s", "level": "VERBOSE", "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "-8483143": { - "message": "No root task above target root task=%s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" + "-7596917112222697106": { + "message": "Waiting for screen on due to %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "-4263657": { - "message": "Got a buffer for request id=%d but latest request is id=%d. Since the buffer is out-of-date, drop it. win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/WindowState.java" + "-8472961767591168851": { + "message": "Sleep needs to pause %s", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "1877956": { - "message": "Content Recording: Display %d should start recording, but don't yet since the task is in PIP", + "-1472885369931482317": { + "message": "Sleep still waiting to pause %s", "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "3593205": { - "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b", + "-2693016397674039814": { + "message": "Sleep still need to stop %d activities", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WallpaperWindowToken.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "9803449": { - "message": "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "8892147402270850613": { + "message": "resumeTopActivity: Skip resume: some activity pausing.", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "10608884": { - "message": " FREEZE %s: CREATE", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + "958293038551087087": { + "message": "resumeTopActivity: Top activity resumed %s", + "level": "DEBUG", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "11060725": { - "message": "Attempted to get system decors flag of a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "4340810061306869942": { + "message": "resumeTopActivity: Going to sleep and all paused", + "level": "DEBUG", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "17696244": { - "message": "startAnimation(): mPendingStart=%b mCanceled=%b", + "-7681635901109618685": { + "message": "resumeTopActivity: Pausing %s", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "33989965": { - "message": " Met condition %s for #%d (%d left)", + "-3463034909521330970": { + "message": "resumeTopActivity: Skip resume: need to start pausing", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "34106798": { - "message": "Content Recording: Display %d state was (%d), is now (%d), so update recording?", + "-2264725269594226780": { + "message": "resumeTopActivity: Top activity resumed (dontWaitForPause) %s", + "level": "DEBUG", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" + }, + "-8359248677489986541": { + "message": "Moving to RESUMED: %s (in existing)", "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "34682671": { - "message": "Not moving display (displayId=%d) to top. Top focused displayId=%d. Reason: FLAG_STEAL_TOP_FOCUS_DISABLED", + "2088177629189452176": { + "message": "Activity config changed during resume: %s, new next: %s", "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "35398067": { - "message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d", + "-8483536760290526299": { + "message": "resumeTopActivity: Resumed %s", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "45285419": { - "message": "startingWindow was set but startingSurface==null, couldn't remove", + "-4911500660485375799": { + "message": "Resume failed; resetting state to %s: %s", "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "51200510": { - "message": " BLACK %s: DESTROY", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/BlackFrame.java" - }, - "51628177": { - "message": "Attempted to get windowing mode of a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "51927339": { - "message": "Skipping %s: voice session", + "3723891427717889172": { + "message": "resumeTopActivity: Restarting %s", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "61363198": { - "message": "Auto-PIP allowed, requesting PIP mode via requestStartTransition(): %s, willAutoPip: %b", + "1529152423206006904": { + "message": "startPausing: taskFrag =%s mResumedActivity=%s", "level": "DEBUG", "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "74885950": { - "message": "Waiting for top state to be released by %s", + "136971836458873178": { + "message": "Moving to PAUSING: %s", "level": "VERBOSE", "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "83950285": { - "message": "removeAnimation(%d)", + "-208996201631695262": { + "message": "Auto-PIP allowed, requesting PIP mode via requestStartTransition(): %s, willAutoPip: %b", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "95216706": { - "message": "hideIme target: %s ", + "-4123447037565780632": { + "message": "Auto-PIP allowed, entering PIP mode directly: %s, didAutoPip: %b", "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "95902367": { - "message": "Relayout of %s: focusMayChange=%b", + "-3710776151994843320": { + "message": "Key dispatch not paused for screen off", "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "100936473": { - "message": "Wallpaper animation!", + "8543865526552245064": { + "message": "Activity not running or entered PiP, resuming next.", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "102618780": { - "message": "resumeTopActivity: Pausing %s", - "level": "DEBUG", "group": "WM_DEBUG_STATES", "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "108170907": { - "message": "Add starting %s: startingData=%s", + "1917394294249960915": { + "message": "Enqueueing pending pause: %s", "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "112145970": { - "message": " SKIP: its sibling was rejected", + "-8936154984341817384": { + "message": "Complete pause: %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "114070759": { - "message": "New wallpaper target: %s prevTarget: %s caller=%s", + "4971958459026584561": { + "message": "Executing finish of activity: %s", "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "115358443": { - "message": "Focus changing: %s -> %s", - "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-7113165071559345173": { + "message": "Enqueue pending stop if needed: %s wasStopping=%b visibleRequested=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "138097009": { - "message": "NOSENSOR override is absent: reverting", + "-3777748052684097788": { + "message": "App died during pause, not stopping: %s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java" + "group": "WM_DEBUG_STATES", + "at": "com\/android\/server\/wm\/TaskFragment.java" }, - "140319294": { - "message": "IME target changed within ActivityRecord", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + "-2808577027789344626": { + "message": "TaskFragment appeared name=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "146871307": { - "message": "Tried to remove starting window but startingWindow was null: %s", + "-3582112419663037270": { + "message": "TaskFragment vanished name=%s", "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "150351993": { - "message": "addWindow: %s startingWindow=%s", + "3294593748816836746": { + "message": "TaskFragment info changed name=%s", "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "152914409": { - "message": " BLACK %s: CREATE layer=%d", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/BlackFrame.java" + "5007230330523630579": { + "message": "TaskFragment parent info changed name=%s parentTaskId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "155482615": { - "message": "Focus requested for window=%s", + "6475066005515810081": { + "message": "Sending TaskFragment error exception=%s", "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/InputMonitor.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "174572959": { - "message": "DisplayArea info changed name=%s", + "-7893265697482064583": { + "message": "Activity=%s reparent to taskId=%d", "level": "VERBOSE", "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "182319432": { - "message": " remove from targets %s", + "7048981249808281819": { + "message": "Defer transition id=%d for TaskFragmentTransaction=%s", "level": "VERBOSE", "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "184362060": { - "message": "screenshotTask(%d): mCanceled=%b", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + "-1315509853595025526": { + "message": "Deferred transition id=%d has been continued before the TaskFragmentTransaction=%s is finished", + "level": "WARN", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "184610856": { - "message": "Start calculating TransitionInfo based on participants: %s", + "7421521217481553621": { + "message": "Continue transition id=%d for TaskFragmentTransaction=%s", "level": "VERBOSE", "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "186668272": { - "message": "Now changing app %s", + "3509684748201636981": { + "message": "Register task fragment organizer=%s uid=%d pid=%d", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "189628502": { - "message": "Moving to STOPPING: %s (stop requested)", + "-6777461169027010201": { + "message": "Unregister task fragment organizer=%s uid=%d pid=%d", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "191486492": { - "message": "handleNotObscuredLocked: %s was holding screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by%s", - "level": "DEBUG", - "group": "WM_DEBUG_KEEP_SCREEN_ON", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "200829729": { - "message": "ScreenRotationAnimation onAnimationEnd", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "202263690": { - "message": "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s", + "1327792561585467865": { + "message": "Register remote animations for organizer=%s uid=%d pid=%d", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "210750281": { - "message": "applyAnimationUnchecked, control: %s, task: %s, transit: %s", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/Task.java" + "-2524361347368208519": { + "message": "Unregister remote animations for organizer=%s uid=%d pid=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" }, - "215077284": { - "message": "Animation start delayed for %s", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/SurfaceAnimator.java" + "-6181189296332065162": { + "message": "Task appeared taskId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "221540118": { - "message": "mUserActivityTimeout set to %d", - "level": "DEBUG", - "group": "WM_DEBUG_KEEP_SCREEN_ON", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "6535296991997214354": { + "message": "Task vanished taskId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "232317536": { - "message": "Set intercept back pressed on root=%b", + "-6638141753476761854": { + "message": "Task info changed taskId=%d", "level": "VERBOSE", "group": "WM_DEBUG_WINDOW_ORGANIZER", "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "240271590": { - "message": "moveFocusableActivityToTop: unfocusable activity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-8100069665346602959": { + "message": "Task back pressed on root taskId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "241961619": { - "message": "Adding %s to %s", + "-610138383571469481": { + "message": "Register task organizer=%s uid=%d", "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowToken.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "246676969": { - "message": "Attempted to add window with non-application token .%s Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "1705860547080436016": { + "message": "Unregister task organizer=%s uid=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "248210157": { - "message": "Finishing remote animation", - "level": "INFO", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "-2286607251115721394": { + "message": "createRootTask unknown displayId=%d", + "level": "ERROR", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "251812577": { - "message": "Register display organizer=%s uid=%d", + "8466395828406204368": { + "message": "Create root task displayId=%d winMode=%d", "level": "VERBOSE", "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" - }, - "254883724": { - "message": "addWindowToken: Attempted to add binder token: %s for already created window token: %s displayId=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "255339989": { - "message": "setFocusedRootTask: taskId=%d", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "6867170298997192615": { + "message": "Delete root task display=%d winMode=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "255692476": { - "message": "**** GOOD TO GO", + "-4296644831871159510": { + "message": "Set intercept back pressed on root=%b", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "259206414": { - "message": "Creating Transition: %s", + "-558727273888268534": { + "message": "Restart top activity process of Task taskId=%d", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "261227010": { - "message": "Content Recording: Unable to tell log windowing mode change: %s", - "level": "ERROR", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "-7064081458956324316": { + "message": "Update camera compat control state to %s for taskId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/TaskOrganizerController.java" }, - "269576220": { - "message": "Resuming rotation after drag", + "3007492640459931179": { + "message": "Pausing rotation during re-position", "level": "DEBUG", "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DragState.java" + "at": "com\/android\/server\/wm\/TaskPositioner.java" }, - "269976641": { - "message": "goodToGo(): Animation canceled already", + "5478864901888225320": { + "message": "Resuming rotation after re-position", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/TaskPositioner.java" }, - "273212558": { - "message": " info=%s", + "-2700498872917476567": { + "message": "Starting a Recents transition which can be parallel.", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "274773837": { - "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL transit=%s Callers=%s", + "-8676279589273455859": { + "message": "Transition %d: Set %s as transient-launch", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "283489582": { - "message": "Clear animatingExit: reason=exitAnimationDone win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "288485303": { - "message": "Attempted to set remove mode to a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "289967521": { - "message": "Check opening app=%s: allDrawn=%b startingDisplayed=%b startingMoved=%b isRelaunching()=%b startingWindow=%s", + "2734227875286695843": { + "message": "Override sync-method for %s because seamless rotating", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "292904800": { - "message": "Deferring rotation, animation in progress.", + "2808217645990556209": { + "message": "Starting Transition %d", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "295861935": { - "message": "startLockTaskMode: %s", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "-4672522645315112127": { + "message": "Collecting in transition %d: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "302969511": { - "message": "Task info changed taskId=%d", + "65881049096729394": { + "message": " Creating Ready-group for Transition %d with root=%s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "302992539": { - "message": "addAnimation(%s)", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + "1101215730201607371": { + "message": "Existence Changed in transition %d: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "306524472": { - "message": "Stop failed; moving to STOPPED: %s", + "-3942072270654590479": { + "message": "Set transition ready=%b %d", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "312030608": { - "message": "New topFocusedDisplayId=%d", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "-4688704756793656554": { + "message": " Commit activity becoming invisible: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "315395835": { - "message": "Trying to add window with invalid user=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "1817207111271920503": { + "message": " Skipping post-transition snapshot for task %d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "323235828": { - "message": "Delaying app transition for recents animation to finish", + "-2960171012238790176": { + "message": " Commit wallpaper becoming invisible: %s", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "327461496": { - "message": "Complete pause: %s", + "1230784960534033968": { + "message": "Aborting Transition: %d", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "339482207": { - "message": "Content Recording: Display %d was already recording, so apply transformations if necessary", + "-892865733969888022": { + "message": "Force Playing Transition: %d", "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "341055768": { - "message": "resumeTopActivity: Skip resume: need to start pausing", + "-1354622424895965634": { + "message": "#%d: Met condition: %s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "341360111": { - "message": "selectAnimation in %s: transit=%d", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/DisplayPolicy.java" + "-5350671621840749173": { + "message": "Calling onTransitionReady: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "342460966": { - "message": "DRAG %s: pos=(%d,%d)", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/DragState.java" + "1830385055586991567": { + "message": "Apply and finish immediately because player is disabled for transition #%d .", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "344795667": { - "message": "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b mOpeningApps.size()=%d mClosingApps.size()=%d mChangingApps.size()=%d", + "-758501334967569539": { + "message": " SKIP: %s", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransition.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "350168164": { - "message": "Removing activity %s, reason= %s callers=%s", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-2714847784842612086": { + "message": " SKIP: is wallpaper", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "355720268": { - "message": "stopFreezingDisplayLocked: Unfreezing now", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "1855461834864671586": { + "message": " check sibling %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "360319850": { - "message": "fractionRendered scale=%f", + "-6292043690918793069": { + "message": " SKIP: sibling is visible but not part of transition", "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "364992694": { - "message": "freezeDisplayRotation: current rotation=%d, new rotation=%d, caller=%s", + "7897657428993391672": { + "message": " unrelated invisible sibling %s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "371173718": { - "message": "finishSync cancel=%b for %s", + "3873493605120555608": { + "message": " sibling is a participant with mode %s", "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/WindowContainer.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "371641947": { - "message": "Window Manager Crash %s", - "level": "WTF", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "7665553560859456426": { + "message": " SKIP: common mode mismatch. was %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "372792199": { - "message": "Non-null activity for system window of rootType=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-8916099332247176657": { + "message": " checking %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "374506950": { - "message": "Reporting activity moved to display, activityRecord=%s, displayId=%d, config=%s", + "-6818387694968032301": { + "message": " SKIP: its sibling was rejected", "level": "VERBOSE", - "group": "WM_DEBUG_SWITCH", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "374972436": { - "message": "performEnableScreen: Waiting for anim complete", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-7326702978448933012": { + "message": " keep as target %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "378825104": { - "message": "Enqueueing pending pause: %s", + "943961036184959431": { + "message": " remove from targets %s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "378890013": { - "message": "Apply and finish immediately because player is disabled for transition #%d .", + "841543868388687804": { + "message": " CAN PROMOTE: promoting to parent %s", "level": "VERBOSE", "group": "WM_DEBUG_WINDOW_TRANSITIONS", "at": "com\/android\/server\/wm\/Transition.java" }, - "385237117": { - "message": "moveFocusableActivityToTop: already on top and focused, activity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "743586316159041023": { + "message": "Start calculating TransitionInfo based on participants: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "385595355": { - "message": "Starting animation on %s: type=%d, anim=%s", + "-7247430213293162757": { + "message": " Rejecting as detached: %s", "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "390947100": { - "message": "Screenshotting %s [%s]", + "-5811837191094192313": { + "message": " Rejecting as no-op: %s", "level": "VERBOSE", "group": "WM_DEBUG_WINDOW_TRANSITIONS", "at": "com\/android\/server\/wm\/Transition.java" }, - "397382873": { - "message": "Moving to PAUSED: %s %s", + "-1153926883525904120": { + "message": " Initial targets: %s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "397862437": { - "message": "Cancelling animation restarting=%b for %s", - "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/SurfaceAnimator.java" + "-9191328656870721224": { + "message": " Final targets: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "399841913": { - "message": "SURFACE RECOVER DESTROY: %s", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "-2971560715211489406": { + "message": " Add condition %s for #%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "405146734": { - "message": " Final targets: %s", + "7631061720069910622": { + "message": " Met condition %s for #%d (%d left)", "level": "VERBOSE", "group": "WM_DEBUG_WINDOW_TRANSITIONS", "at": "com\/android\/server\/wm\/Transition.java" }, - "416924848": { - "message": "InsetsSource Control %s for target %s", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" + "-4770394322045550928": { + "message": " Setting Ready-group to %b. group=%s from %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "417311568": { - "message": "onResize: Resizing %s", - "level": "DEBUG", - "group": "WM_DEBUG_RESIZE", - "at": "com\/android\/server\/wm\/WindowState.java" + "6039132370452820927": { + "message": " Setting allReady override", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "419378610": { - "message": "Content Recording: Apply transformations of shift %d x %d, scale %f x %f, crop (aka recorded content size) %d x %d for display %d; display has size %d x %d; surface has size %d x %d", + "-3263748870548668913": { + "message": " allReady query: used=%b override=%b defer=%d states=[%s]", "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "422634333": { - "message": "First draw done in potential wallpaper target %s", + "2699903406935781477": { + "message": "Screenshotting %s [%s]", "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/Transition.java" }, - "424524729": { - "message": "Attempted to add wallpaper window with unknown token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-233096875591058130": { + "message": "Creating Transition: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "431715812": { - "message": "Launch on display check: allow launch any on display", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + "2154694726162725342": { + "message": "Start collecting in Transition: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "435494046": { - "message": "Attempted to add window to a display for which the application does not have access: %d. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-4235778637051052061": { + "message": "Disabling player for transition #%d because display isn't enabled yet", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "463993897": { - "message": "Aborted waiting for drawn: %s", - "level": "WARN", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "4005704720444963797": { + "message": "Requesting StartTransition: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "485170982": { - "message": "Not finishing noHistory %s on stop because we're just sleeping", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-6030030735787868329": { + "message": "Finish Transition: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "487621047": { - "message": "DisplayArea vanished name=%s", + "-1611886029896664304": { + "message": "Moving #%d from collecting to waiting.", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "508887531": { - "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", + "-7097461682459496366": { + "message": "Playing #%d in parallel on track #%d", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "528150092": { - "message": " keep as target %s", + "-7364464699035275052": { + "message": "Marking #%d animation as SYNC.", "level": "VERBOSE", "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "531242746": { - "message": " THUMBNAIL %s: CREATE", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowContainerThumbnail.java" + "-5509640937151643757": { + "message": "Queueing transition: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "531891870": { - "message": "Previous Destination is Activity:%s Task:%s removedContainer:%s, backType=%s", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" + "-2741593375634604522": { + "message": "Queueing legacy sync-set: %s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "532771960": { - "message": "Adding untrusted state listener=%s with id=%d", - "level": "DEBUG", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + "-5051723169912572741": { + "message": "%s", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "535103992": { - "message": "Wallpaper may change! Adjusting", + "4281568181321808508": { + "message": " startWCT=%s", "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "539077569": { - "message": "Clear freezing of %s force=%b", + "5141999957143860655": { + "message": " info=%s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", + "at": "com\/android\/server\/wm\/TransitionController.java" }, - "544101314": { - "message": "performEnableScreen: Waited %dms for all windows to be drawn", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "3445530300764535903": { + "message": "unregister failed, couldn't find deathRecipient for %s with id=%d", + "level": "ERROR", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "556758086": { - "message": "Applying new update lock state '%s' for %s", + "-6140852484700685564": { + "message": "Registering listener=%s with id=%d for window=%s with %s", "level": "DEBUG", - "group": "WM_DEBUG_IMMERSIVE", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "557227556": { - "message": "onAnimationFinished(): Notify animation finished:", + "3691097873058247482": { + "message": "Unregistering listener=%s with id=%d", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "558823034": { - "message": "SURFACE isOpaque=%b: %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + "6408851516381868623": { + "message": "Checking %d windows", + "level": "VERBOSE", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "573582981": { - "message": "reparent: moving activity=%s to new task fragment in task=%d at %d", - "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "7718187745767272532": { + "message": "Skipping %s", + "level": "VERBOSE", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "579298675": { - "message": "Moving to DESTROYED: %s (removed from history)", + "-1135667737459933313": { + "message": "coveredRegionsAbove updated with %s frame:%s region:%s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "585096182": { - "message": "SURFACE isColorSpaceAgnostic=%b: %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + "854487339271667012": { + "message": "checkIfInThreshold fractionRendered=%f alpha=%f currTimeMs=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "585839596": { - "message": "call showInsets(ime) on %s", - "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + "-2248576188205088843": { + "message": "lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f minFractionRendered=%f", + "level": "VERBOSE", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "594260577": { - "message": "createWallpaperAnimations()", + "6236170793308011579": { + "message": "Adding untrusted state listener=%s with id=%d", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "600140673": { - "message": "checkBootAnimationComplete: Waiting for anim complete", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "601283564": { - "message": "Dream packageName does not match active dream. Package %s does not match %s", - "level": "ERROR", - "group": "WM_DEBUG_DREAM", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" - }, - "605179032": { - "message": "checkIfInThreshold fractionRendered=%f alpha=%f currTimeMs=%d", - "level": "VERBOSE", "group": "WM_DEBUG_TPL", "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "608694300": { - "message": " NEW SURFACE SESSION %s", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/Session.java" + "5405816744363636527": { + "message": "Adding trusted state listener=%s with id=%d", + "level": "DEBUG", + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "612856628": { - "message": "Content Recording: Stop MediaProjection on virtual display %d", + "-5162728346383863020": { + "message": "computeFractionRendered: visibleRegion=%s screenBounds=%s contentSize=%s scale=%f,%f", "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "620519522": { - "message": "findFocusedWindow: No focusable windows, display=%d", + "898769258643799441": { + "message": "fractionRendered scale=%f", "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "628276090": { - "message": "Delaying app transition for screen rotation animation to finish", + "-455501334697331596": { + "message": "fractionRendered boundsOverSource=%f", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "631792420": { - "message": "Attempted to add window with token that is not a window: %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_TPL", + "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" }, - "638429464": { - "message": "\tRemove container=%s", + "1964980935866463086": { + "message": "\tWallpaper of display=%s is not visible", "level": "DEBUG", "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" }, - "644675193": { - "message": "Real start recents", + "8131665298937888044": { + "message": "startAnimation", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" }, - "646155519": { - "message": "Started intent=%s", + "8030745595351281943": { + "message": "onAnimationCancelled", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" - }, - "646981048": { - "message": "Invalid displayId for requestScrollCapture: %d", - "level": "ERROR", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "662572728": { - "message": "Attempted to add a toast window with bad token %s. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_REMOTE_ANIMATIONS", + "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" }, - "665256544": { - "message": "All windows drawn!", + "-5254364639040552989": { + "message": "Hiding wallpaper %s from %s target=%s prev=%s callers=%s", "level": "DEBUG", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "666937535": { - "message": "attachWindowContextToDisplayArea: trying to attach to a non-existing display:%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_WALLPAPER", + "at": "com\/android\/server\/wm\/WallpaperController.java" }, - "669361121": { - "message": "Sleep still need to stop %d activities", + "-3477087868568520027": { + "message": "No longer animating wallpaper targets!", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_WALLPAPER", + "at": "com\/android\/server\/wm\/WallpaperController.java" }, - "674932310": { - "message": "Setting Intent of %s to target %s", + "-3751289048117070874": { + "message": "New wallpaper target: %s prevTarget: %s caller=%s", "level": "VERBOSE", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/Task.java" - }, - "675705156": { - "message": "resumeTopActivity: Top activity resumed %s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_WALLPAPER", + "at": "com\/android\/server\/wm\/WallpaperController.java" }, - "685047360": { - "message": "Resizing window %s", + "5625223922466895079": { + "message": "New animation: %s old animation: %s", "level": "VERBOSE", - "group": "WM_DEBUG_RESIZE", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_WALLPAPER", + "at": "com\/android\/server\/wm\/WallpaperController.java" }, - "686185515": { - "message": "Resize reasons for w=%s: %s configChanged=%b didFrameInsetsChange=%b", + "7634524672408826188": { + "message": "Animating wallpapers: old: %s hidden=%b new: %s hidden=%b", "level": "VERBOSE", - "group": "WM_DEBUG_RESIZE", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_WALLPAPER", + "at": "com\/android\/server\/wm\/WallpaperController.java" }, - "691515534": { - "message": " Commit wallpaper becoming invisible: %s", + "-4345077332231178044": { + "message": "Old wallpaper still the target.", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "693423992": { - "message": "setAnimationLocked: setting mFocusMayChange true", - "level": "INFO", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_DEBUG_WALLPAPER", + "at": "com\/android\/server\/wm\/WallpaperController.java" }, - "701366755": { - "message": "Attempt to transfer touch gesture with non-existent embedded window", - "level": "WARN", - "group": "WM_DEBUG_EMBEDDED_WINDOWS", - "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" + "-2504764636812266719": { + "message": "New wallpaper: target=%s prev=%s", + "level": "DEBUG", + "group": "WM_DEBUG_WALLPAPER", + "at": "com\/android\/server\/wm\/WallpaperController.java" }, - "704998117": { - "message": "Failed to create surface control for %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-7936547457136708587": { + "message": "Wallpaper token %s visible=%b", + "level": "DEBUG", + "group": "WM_DEBUG_WALLPAPER", + "at": "com\/android\/server\/wm\/WallpaperWindowToken.java" }, - "708142634": { - "message": "Top resumed state released %s", + "7214407534407465113": { + "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/WallpaperWindowToken.java" }, - "715749922": { - "message": "Allowlisting %d:%s", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "-5360147928134631656": { + "message": ">>> OPEN TRANSACTION animate", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowAnimator.java" }, - "723575093": { - "message": "Attempted to add window with a client %s that is dead. Aborting.", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-3993586364046165922": { + "message": "<<< CLOSE TRANSACTION animate", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowAnimator.java" }, - "726205185": { - "message": "Moving to DESTROYED: %s (destroy skipped)", + "-5231580410559054259": { + "message": "%s is requesting orientation %d (%s)", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "733466617": { - "message": "Wallpaper token %s visible=%b", - "level": "DEBUG", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperWindowToken.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "736692676": { - "message": "Config is relaunching %s", + "6949303417875346627": { + "message": "Starting animation on %s: type=%d, anim=%s", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "743418423": { - "message": "Sending TaskFragment error exception=%s", + "-8730310387200541562": { + "message": "applyAnimation: transition animation is disabled or skipped. container=%s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "744171317": { - "message": " SKIP: %s", + "2363818604357955690": { + "message": "applyAnimation: transit=%s, enter=%b, wc=%s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "745391677": { - "message": " CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + "2262119454684034794": { + "message": "applyAnimation: container=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", + "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "765395228": { - "message": "onAnimationFinished(): controller=%s reorderMode=%d", + "5857165752965610762": { + "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "769218938": { + "9017113545720281233": { "message": "Loaded animation %s for %s, duration: %d, stack=%s", "level": "INFO", "group": "WM_DEBUG_ANIM", "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "781471998": { - "message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" - }, - "782864973": { - "message": "Releasing screen wakelock, obscured by %s", - "level": "DEBUG", - "group": "WM_DEBUG_KEEP_SCREEN_ON", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "791468751": { - "message": "Pausing rotation during re-position", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/TaskPositioner.java" + "5272307326252759722": { + "message": "onSyncFinishedDrawing %s", + "level": "VERBOSE", + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "793568608": { - "message": " SKIP: sibling is visible but not part of transition", + "-8311909671193661340": { + "message": "setSyncGroup #%d on %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "794570322": { - "message": "Now closing app %s", + "-3871009616397322067": { + "message": "finishSync cancel=%b for %s", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "801521566": { - "message": "Content Recording: Attempting to mirror %d from %d but no DisplayContent associated. Changing to mirror default display.", - "level": "WARN", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "-4267530270533009730": { + "message": "Error sending initial configuration change to WindowContainer overlay", + "level": "ERROR", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "806891543": { - "message": "Setting mOrientationChangeComplete=true because wtoken %s numInteresting=%d numDrawn=%d", - "level": "INFO", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "5179630990780610966": { + "message": "Error sending initial insets change to WindowContainer overlay", + "level": "ERROR", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowContainer.java" }, - "810599500": { - "message": "SURFACE isSecure=%b: %s", + "-131600102855790053": { + "message": " THUMBNAIL %s: CREATE", "level": "INFO", "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "824532141": { - "message": "lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f minFractionRendered=%f", - "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" - }, - "829434921": { - "message": "Draw state now committed in %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + "at": "com\/android\/server\/wm\/WindowContainerThumbnail.java" }, - "835814848": { - "message": "%s", + "2163930285157267092": { + "message": "The listener does not exist.", "level": "INFO", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "851368695": { - "message": "Deferred transition id=%d has been continued before the TaskFragmentTransaction=%s is finished", - "level": "WARN", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "872933199": { - "message": "Changing focus from %s to %s displayId=%d Callers=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" - }, - "873160948": { - "message": "Activity=%s reparent to taskId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowContextListenerController.java" }, - "873914452": { - "message": "goodToGo()", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "6139364662459841509": { + "message": "Could not register window container listener token=%s, container=%s", + "level": "ERROR", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowContextListenerController.java" }, - "892244061": { - "message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d", - "level": "INFO", - "group": "WM_DEBUG_SCREEN_ON", + "3655576047584951173": { + "message": "Window Manager Crash %s", + "level": "WTF", + "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "895158150": { - "message": "allPausedActivitiesComplete: r=%s state=%s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" - }, - "898863925": { - "message": "Attempted to add QS dialog window with unknown token %s. Aborting.", + "-3029436704707366221": { + "message": "Attempted to add window with a client %s that is dead. Aborting.", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "906215061": { - "message": "Apply window transaction, syncId=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/WindowOrganizerController.java" - }, - "913494177": { - "message": "removeAllWindowsIfPossible: removing win=%s", + "-1303710477998542095": { + "message": "Attempted to add window to a display that does not exist: %d. Aborting.", "level": "WARN", - "group": "WM_DEBUG_WINDOW_MOVEMENT", - "at": "com\/android\/server\/wm\/WindowToken.java" - }, - "916191774": { - "message": "Orientation change complete in %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "935418348": { - "message": "resumeTopActivity: Skip resume: some activity pausing.", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" - }, - "937080808": { - "message": "Content Recording: Recorded task is removed, so stop recording on display %d", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "939638078": { - "message": "config_deviceTabletopRotations is not defined. Half-fold letterboxing will work inconsistently.", + "8039410207325630747": { + "message": "Attempted to add window to a display for which the application does not have access: %d. Aborting.", "level": "WARN", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "948208142": { - "message": "Setting Activity.mLauncherTaskBehind to true. Activity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "950074526": { - "message": "setLockTaskMode: Can't lock due to auth", + "-3451016577701561221": { + "message": "Window %s is already added", "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "954470154": { - "message": "FORCED DISPLAY SCALING DISABLED", - "level": "INFO", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "956374481": { - "message": "removeLockedTask: task=%s last task, reverting locktask mode. Callers=%s", - "level": "DEBUG", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "958338552": { - "message": "grantEmbeddedWindowFocus win=%s dropped focus so setting focus to null since no candidate was found", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS", + "7245919222637411747": { + "message": "Attempted to add window with token that is not a window: %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "959486822": { - "message": "setSyncGroup #%d on %s", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "966569777": { - "message": "SyncGroup %d: onSurfacePlacement checking %s", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" - }, - "969323241": { - "message": "Sending new config to %s, config: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "972354148": { - "message": "\tcontainer=%s", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" - }, - "975028389": { - "message": "unable to call receiver for empty keyboard shortcuts", - "level": "ERROR", + "-8579305050440451727": { + "message": "Attempted to add window with token that is a sub-window: %s. Aborting.", + "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "975275467": { - "message": "Set animatingExit: reason=remove\/isAnimating win=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" + "-1075040941127814341": { + "message": "Attempted to add private presentation window to a non-private display. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "979347997": { - "message": "Launch on display check: disallow activity embedding without permission.", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + "7599690046549866326": { + "message": "Attempted to add presentation window to a non-suitable display. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "987903142": { - "message": "Sleep needs to pause %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "-2546047231197102533": { + "message": "Trying to add window with invalid user=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "996960396": { - "message": "Starting Transition %d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "3713874359318494804": { + "message": "Attempted to add window with non-application token .%s Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1001904964": { - "message": "***** BOOT TIMEOUT: forcing display enabled", + "-6507147599943157469": { + "message": "Attempted to add window with exiting application token .%s Aborting.", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1015746067": { - "message": "Display id=%d is ignoring orientation request for %d, return %d following a per-app override for %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "-1409483453189443362": { + "message": "Attempted to add starting window to token with already existing starting window", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1022095595": { - "message": "TaskFragment info changed name=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + "-1806907994917883598": { + "message": "Attempted to add starting window to token but already cleaned", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1023413388": { - "message": "Finish waiting for pause of: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-5450131464624918523": { + "message": "Attempted to add input method window with bad token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1030898920": { - "message": "notifyInsetsControlChanged for %s ", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/WindowState.java" + "-6484128707849211138": { + "message": "Attempted to add voice interaction window with bad token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1033274509": { - "message": "moveWindowTokenToDisplay: Attempted to move non-existing token: %s", + "7768591536609704658": { + "message": "Attempted to add wallpaper window with bad token %s. Aborting.", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1040675582": { - "message": "Can't report activity configuration update - client not running, activityRecord=%s", + "7497077135474110999": { + "message": "Attempted to add Accessibility overlay window with bad token %s. Aborting.", "level": "WARN", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1042363394": { - "message": "Attempt to transfer touch gesture using a host window with no input channel", + "8957851092580119204": { + "message": "Attempted to add a toast window with bad token %s. Aborting.", "level": "WARN", - "group": "WM_DEBUG_EMBEDDED_WINDOWS", - "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1046228706": { - "message": "Defer transition id=%d for TaskFragmentTransaction=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + "-1945746969404688952": { + "message": "Attempted to add QS dialog window with bad token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1046922686": { - "message": "requestScrollCapture: caught exception dispatching callback: %s", + "3419934373251134563": { + "message": "Non-null activity for system window of rootType=%d", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1047505501": { - "message": "notifyInsetsChanged for %s ", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/WindowState.java" + "-1161056447389155729": { + "message": "Adding more than one toast window for UID at a time.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1047769218": { - "message": "Finishing activity r=%s, result=%d, data=%s, reason=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-7518552252637236411": { + "message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1049367566": { - "message": "Sending to proc %s new config %s", + "-6055615852717459196": { + "message": "addWindow: %s startingWindow=%s", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/WindowProcessController.java" + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1051545910": { - "message": "Exit animation finished in %s: remove=%b", + "-2829980616540274784": { + "message": "addWindow: New client %s: window=%s Callers=%s", "level": "VERBOSE", "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "1068803972": { - "message": "Activity paused: token=%s, timeout=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1073230342": { - "message": "startAnimation", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" + "-7315179333005789167": { + "message": "Attempted to add application window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1075460705": { - "message": "Continue transition id=%d for TaskFragmentTransaction=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + "-7547709658889961930": { + "message": "Attempted to add input method window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1087494661": { - "message": "Clear window stuck on animatingExit status: %s", + "3009864422591182484": { + "message": "Attempted to add voice interaction window with unknown token %s. Aborting.", "level": "WARN", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowState.java" + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1088929964": { - "message": "onLockTaskPackagesUpdated: starting new locktask task=%s", - "level": "DEBUG", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" + "-2639914438438144071": { + "message": "Attempted to add wallpaper window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1089714158": { - "message": " FREEZE %s: DESTROY", - "level": "INFO", - "group": "WM_SHOW_SURFACE_ALLOC", - "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + "-7529563697886120786": { + "message": "Attempted to add QS dialog window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1090378847": { - "message": "Checking %d windows", - "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + "4253401518117961686": { + "message": "Attempted to add Accessibility overlay window with unknown token %s. Aborting.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1100065297": { - "message": "Attempted to get IME policy of a display that does not exist: %d", + "5834230650841873680": { + "message": "Attempted to add a toast window with unknown token %s. Aborting.", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1105210816": { - "message": "Skipping config check in destroyed state %s", + "5265273548711408921": { + "message": "postWindowRemoveCleanupLocked: %s", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "1112047265": { - "message": "finishDrawingWindow: %s mDrawState=%s", - "level": "DEBUG", "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1115248873": { - "message": "Calling onTransitionReady: %s", + "-3847568084407666790": { + "message": "Final remove of window: %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" - }, - "1115417974": { - "message": "FORCED DISPLAY SIZE: %dx%d", - "level": "INFO", - "group": "WM_ERROR", + "group": "WM_DEBUG_WINDOW_MOVEMENT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1126328412": { - "message": "Scheduling idle now: forceIdle=%b immediate=%b", + "1419572818243106725": { + "message": "Removing %s from %s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1140424002": { - "message": "Finished screen turning on...", + "8312693933819247897": { + "message": "Relayout %s: oldVis=%d newVis=%d. %s", "level": "INFO", "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/DisplayPolicy.java" + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1145016093": { - "message": "Content Recording: Attempting to mirror self on %d", + "8319702790708803735": { + "message": "Exception thrown when creating surface for client %s (%s). %s", "level": "WARN", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1149424314": { - "message": "Unregister display organizer=%s uid=%d", + "212929172223901460": { + "message": "Relayout of %s: focusMayChange=%b", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1151072840": { - "message": "collectTaskRemoteAnimations, target: %s", + "-255991894956556845": { + "message": "Set animatingExit: reason=startExitingAnimation\/%s win=%s", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "1164325516": { - "message": "onExitAnimationDone in %s: exiting=%b remove=%b selfAnimating=%b anim=%s", - "level": "VERBOSE", "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "1166381079": { - "message": "Execute app transition: %s, displayId: %d Callers=%s", - "level": "WARN", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1175495463": { - "message": "ImeContainer just became organized. Reparenting under parent. imeParentSurfaceControl=%s", + "6555160513135851764": { + "message": "OUT SURFACE %s: copied", "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1178653181": { - "message": "Old wallpaper still the target.", - "level": "VERBOSE", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" + "-196459205494031145": { + "message": "Failed to create surface control for %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1191587912": { - "message": "Moved rootTask=%s behind rootTask=%s", + "-5512006943172316333": { + "message": "finishDrawingWindow: %s mDrawState=%s", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1192413464": { - "message": "Comparing existing cls=%s \/aff=%s to new cls=%s \/aff=%s", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "-2577785761087081584": { + "message": "Permission Denial: %s from pid=%d, uid=%d requires %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1208313423": { + "4547566763172245740": { "message": "addWindowToken: Attempted to add token: %s for non-exiting displayId=%d", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1210037962": { - "message": "Register remote animations for organizer=%s uid=%d pid=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" - }, - "1219600119": { - "message": "addWindow: win=%s Callers=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/WindowToken.java" + "-972832559831959983": { + "message": "addWindowToken: Attempted to add binder token: %s for already created window token: %s displayId=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1224184681": { - "message": "No longer Stopped: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "8372202339190060748": { + "message": "attachWindowContextToDisplayArea: calling from non-existing process pid=%d uid=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1224307091": { - "message": "checkBootAnimationComplete: Animation complete!", - "level": "INFO", - "group": "WM_DEBUG_BOOT", + "1904306629015452865": { + "message": "attachWindowContextToDisplayArea: trying to attach to a non-existing display:%d", + "level": "WARN", + "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1239439010": { - "message": "moveFocusableActivityToTop: set focused, activity=%s", - "level": "DEBUG", - "group": "WM_DEBUG_FOCUS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-6845859096032432107": { + "message": "attachWindowContextToDisplayContent: calling from non-existing process pid=%d uid=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1251721200": { - "message": "unregister failed, couldn't find deathRecipient for %s with id=%d", - "level": "ERROR", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + "1473791807245791604": { + "message": "attachWindowContextToWindowToken: calling from non-existing process pid=%d uid=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1252594551": { - "message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d", + "-2056866750160555704": { + "message": "Then token:%s is invalid. It might be removed", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1254403969": { - "message": "Surface returned was null: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-1045756671264607145": { + "message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1264179654": { - "message": "No focused window, defaulting to top current task's window", + "874825105313641295": { + "message": "removeWindowToken: Attempted to remove non-existing token: %s", "level": "WARN", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1270792394": { - "message": "Resumed after relaunch %s", - "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "5128669121055635771": { + "message": "moveWindowTokenToDisplay: Attempted to move token: %s to non-exiting displayId=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1282992082": { - "message": "Disabling player for transition #%d because display isn't enabled yet", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" + "6497954191906583839": { + "message": "moveWindowTokenToDisplay: Attempted to move non-existing token: %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1284122013": { - "message": "TaskFragment appeared name=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + "2865882097969084039": { + "message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1288731814": { - "message": "WindowState.hideLw: setting mFocusMayChange true", + "-886583195545553099": { + "message": "Not moving display (displayId=%d) to top. Top focused displayId=%d. Reason: FLAG_STEAL_TOP_FOCUS_DISABLED", "level": "INFO", "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "1288920916": { - "message": "Error sending initial insets change to WindowContainer overlay", - "level": "ERROR", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "1305412562": { - "message": "Report configuration: %s %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityClientController.java" + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1309365288": { - "message": "Removing dim surface %s on transaction %s", - "level": "DEBUG", - "group": "WM_DEBUG_DIMMER", - "at": "com\/android\/server\/wm\/SmoothDimmer.java" + "-1557387535886241553": { + "message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1316533291": { - "message": "State movement: %s from:%s to:%s reason:%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-6467850045030187736": { + "message": "enableScreenIfNeededLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1325649102": { - "message": "Bad requesting window %s", + "179762478329442868": { + "message": "***** BOOT TIMEOUT: forcing display enabled", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1329340614": { - "message": "Orientation not waiting for draw in %s, surfaceController %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowState.java" + "-3417569256875279779": { + "message": "performEnableScreen: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1330804250": { - "message": "addChild: %s at top.", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/Task.java" + "-7516915153725082358": { + "message": "performEnableScreen: Waited %dms for all windows to be drawn", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1331177619": { - "message": "Attempted to add a toast window with unknown token %s. Aborting.", + "-1541244520024033685": { + "message": "performEnableScreen: Waiting for anim complete", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, + "2670150656385758826": { + "message": "performEnableScreen: bootFinished() failed.", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1335791109": { - "message": "createSurface %s: mDrawState=DRAW_PENDING", + "530628508916855904": { + "message": "******************** ENABLING SCREEN!", "level": "INFO", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" - }, - "1337596507": { - "message": "Sending to proc %s new compat %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/CompatModePackages.java" + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1346895820": { - "message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s", + "5477889324043875194": { + "message": "Notified TransitionController that the display is ready.", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1360176455": { - "message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteDisplayChange=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d", - "level": "DEBUG", - "group": "WM_DEBUG_ORIENTATION", + "-2061779801633179448": { + "message": "checkBootAnimationComplete: Waiting for anim complete", + "level": "INFO", + "group": "WM_DEBUG_BOOT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1364126018": { - "message": "Resumed activity; dropping state of: %s", + "-8177456840019985809": { + "message": "checkBootAnimationComplete: Animation complete!", "level": "INFO", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1364498663": { - "message": "notifyAppResumed: wasStopped=%b %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-333924817004774456": { + "message": "showBootMessage: msg=%s always=%b mAllowBootMessages=%b mShowingBootMessages=%b mSystemBooted=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1373000889": { - "message": "abortShowImePostLayout", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + "2994810644159608200": { + "message": "hideBootMessagesLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1381227466": { - "message": "App is requesting an orientation, return %d for display id=%d", + "-6625203651195752178": { + "message": "freezeDisplayRotation: current rotation=%d, new rotation=%d, caller=%s", "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/TaskDisplayArea.java" - }, - "1382634842": { - "message": "Unregistering listener=%s with id=%d", - "level": "DEBUG", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1393721079": { - "message": "Starting remote display change: from [rot = %d], to [%dx%d, rot = %d]", + "8988910478484254861": { + "message": "thawRotation: mRotation=%d, caller=%s", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java" - }, - "1396893178": { - "message": "createRootTask unknown displayId=%d", - "level": "ERROR", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "1401295262": { - "message": "Mode default, asking user", - "level": "WARN", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" - }, - "1401700824": { - "message": "Window drawn win=%s", - "level": "DEBUG", - "group": "WM_DEBUG_SCREEN_ON", + "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1422781269": { - "message": "Resuming rotation after re-position", - "level": "DEBUG", + "7261084872394224738": { + "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b", + "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/TaskPositioner.java" + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1423418408": { - "message": "unable to restore pointer icon", + "8664813170125714536": { + "message": "View server did not start", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1430336882": { - "message": "findFocusedWindow: focusedApp windows not focusable using new focus @ %s", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "-8019372496359375449": { + "message": "Could not send command %s with parameters %s. %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1434383382": { - "message": "Attempted to get flag of a display that does not exist: %d", + "1893303527772009363": { + "message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1445704347": { - "message": "coveredRegionsAbove updated with %s frame:%s region:%s", - "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + "-3652974372240081071": { + "message": "SAFE MODE ENABLED (menu=%d s=%d dpad=%d trackball=%d)", + "level": "INFO", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1448683958": { - "message": "Override pending remote transitionSet=%b adapter=%s", + "4945624619344146947": { + "message": "SAFE MODE not enabled", "level": "INFO", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransition.java" + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1457990604": { - "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE transit=%s Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" + "-3428027271337724889": { + "message": "Focus changing: %s -> %s", + "level": "INFO", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1460759282": { - "message": "getAnimationTarget in=%s, out=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "1624328195833150047": { + "message": "App freeze timeout expired.", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1463355909": { - "message": "Queueing legacy sync-set: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" + "5830724144971462783": { + "message": "Timeout waiting for drawn: undrawn=%s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1469310004": { - "message": " SKIP: common mode mismatch. was %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "-2240705227895260140": { + "message": "CHECK_IF_BOOT_ANIMATION_FINISHED:", + "level": "INFO", + "group": "WM_DEBUG_BOOT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1473051122": { - "message": "Pausing configuration dispatch for %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "8641557333789260779": { + "message": "FORCED DISPLAY SIZE: %dx%d", + "level": "INFO", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1494644409": { - "message": " Rejecting as detached: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "3781141652793604337": { + "message": "FORCED DISPLAY SCALING DISABLED", + "level": "INFO", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1495525537": { - "message": "createWallpaperAnimations()", - "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + "4117606810523219596": { + "message": "Failed looking up window session=%s callers=%s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1497304204": { - "message": "Deferring rotation, rotation is paused.", + "1233670725456443473": { + "message": "Changing surface while display frozen: %s", "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "1504168072": { - "message": "removeIfPossible: %s callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowState.java" + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1511273241": { - "message": "Refreshing activity for camera compatibility treatment, activityRecord=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java" + "-1716033239040181528": { + "message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d", + "level": "INFO", + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1518495446": { - "message": "removeWindowToken: Attempted to remove non-existing token: %s", + "-4609828204247499633": { + "message": "Aborted waiting for drawn: %s", "level": "WARN", - "group": "WM_ERROR", + "group": "WM_DEBUG_SCREEN_ON", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1519757176": { - "message": "setHomeApp(%s)", + "-7561054602203220590": { + "message": "Window drawn win=%s", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" - }, - "1520642640": { - "message": "Attempt to transfer touch gesture using embedded window with no associated host", - "level": "WARN", - "group": "WM_DEBUG_EMBEDDED_WINDOWS", - "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" - }, - "1521476038": { - "message": "Attempted to set flag to a display that does not exist: %d", - "level": "WARN", - "group": "WM_ERROR", + "group": "WM_DEBUG_SCREEN_ON", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1524174282": { - "message": "Launch on display check: no caller info, skip check", + "2809030008663191766": { + "message": "All windows drawn!", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java" + "group": "WM_DEBUG_SCREEN_ON", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1525976603": { - "message": "cancelAnimation(): reason=%s", + "-1615905649072328410": { + "message": "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimationController.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1528528509": { - "message": "No thumbnail header bitmap for: %s", + "4565793239453546297": { + "message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteDisplayChange=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d", "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "1546187372": { - "message": "Content Recording: Pause the recording session on display %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecordingController.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1557732761": { - "message": "For Intent %s bringing to top: %s", + "-6877112251967196129": { + "message": "stopFreezingDisplayLocked: Unfreezing now", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1563755163": { - "message": "Permission Denial: %s from pid=%d, uid=%d requires %s", - "level": "WARN", + "721393258715103117": { + "message": "%s", + "level": "INFO", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1577579529": { - "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b", - "level": "ERROR", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "1584270979": { - "message": "applyAnimation: container=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/WindowContainer.java" - }, - "1589610525": { - "message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" - }, - "1610646518": { - "message": "Enqueueing pending finish: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "1621562070": { - "message": " startWCT=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "1628345525": { - "message": "Now opening app %s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "1634557978": { + "-5706083447992207254": { "message": "**** Dismissing screen rotation animation", "level": "INFO", "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1635062046": { - "message": "Skipping config check invisible: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "1635462459": { - "message": "onMovedByResize: Moving %s", + "2233371241933584073": { + "message": "Performing post-rotate rotation", "level": "DEBUG", - "group": "WM_DEBUG_RESIZE", - "at": "com\/android\/server\/wm\/WindowState.java" - }, - "1640436199": { - "message": "No app is requesting an orientation, return %d for display id=%d", - "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/TaskDisplayArea.java" - }, - "1653025361": { - "message": "Register task fragment organizer=%s uid=%d pid=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java" + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1653210583": { - "message": "Removing app %s delayed=%b animation=%s animating=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "1010635158502326025": { + "message": "unable to call receiver for empty keyboard shortcuts", + "level": "ERROR", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1658605381": { - "message": "onImeControlTargetChanged %s", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/InsetsStateController.java" + "1278715281433572858": { + "message": "Bad requesting window %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1661414284": { - "message": "Content Recording: Unable to tell MediaProjectionManagerService about resizing the active projection: %s", - "level": "ERROR", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "-707915937966769475": { + "message": "unable to update pointer icon", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1670933628": { - "message": " Setting allReady override", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "-8663841671650918687": { + "message": "unable to restore pointer icon", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1674747211": { - "message": "%s forcing orientation to %d for display id=%d", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayArea.java" + "-6186782212018913664": { + "message": "Invalid displayId for requestScrollCapture: %d", + "level": "ERROR", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1677260366": { - "message": "Finish starting %s: first real window is shown, no animation", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "51378282333944649": { + "message": "requestScrollCapture: caught exception dispatching to window.token=%s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1679569477": { - "message": "Configuration doesn't matter not running %s", - "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-8972916676375201577": { + "message": "requestScrollCapture: caught exception dispatching callback: %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1687944543": { - "message": "Content Recording: Unable to update recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s, since the surface is not available.", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "-1875125162673622728": { + "message": "Attempted to get windowing mode of a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1699269281": { - "message": "Don't organize or trigger events for untrusted displayId=%d", + "3938331948687900219": { + "message": "Attempted to set windowing mode to a display that does not exist: %d", "level": "WARN", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java" + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1712935427": { - "message": "Content Recording: Unable to start recording for display %d since the surface is not available.", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "4200292050699107329": { + "message": "Attempted to get remove mode of a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1720229827": { - "message": "Creating animation bounds layer", - "level": "INFO", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "-5574580669790275797": { + "message": "Attempted to set remove mode to a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1721036256": { - "message": "Attempt to transfer touch gesture using embedded window that has no input channel", + "525945815055875796": { + "message": "Attempted to get flag of a display that does not exist: %d", "level": "WARN", - "group": "WM_DEBUG_EMBEDDED_WINDOWS", - "at": "com\/android\/server\/wm\/EmbeddedWindowController.java" + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1730300180": { - "message": "PendingStartTransaction found", - "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" + "8186524992939307511": { + "message": "Attempted to set flag to a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1735199721": { - "message": "Queueing transition: %s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" + "-600035824255550632": { + "message": "Attempted to get system decors flag of a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1739298851": { - "message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d", + "3056518663346732662": { + "message": "Attempted to set system decors flag to a display that does not exist: %d", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1746778201": { - "message": "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s", - "level": "INFO", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "5177195624625618567": { + "message": "Attempted to get IME policy of a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1750878635": { - "message": "Content Recording: Provided surface for recording on display %d is not present, so do not update the surface", - "level": "VERBOSE", - "group": "WM_DEBUG_CONTENT_RECORDING", - "at": "com\/android\/server\/wm\/ContentRecorder.java" + "3932627933834459400": { + "message": "Attempted to set IME policy to a display that does not exist: %d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1756082882": { - "message": "Orientation change skips hidden %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + "5770211341769258866": { + "message": "setWallpaperShowWhenLocked: non-existent wallpaper token: %s", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1774661765": { - "message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.", + "698926505694016512": { + "message": "setWallpaperCropHints: non-existent wallpaper token: %s", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1781673113": { - "message": "onAnimationFinished(): targetRootTask=%s targetActivity=%s mRestoreTargetBehindRootTask=%s", + "-7428028317216329062": { + "message": "hideIme target: %s ", "level": "DEBUG", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1786463281": { - "message": "Adding trusted state listener=%s with id=%d", + "1006302987953651112": { + "message": "hideIme Control target: %s ", "level": "DEBUG", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1789321832": { - "message": "Then token:%s is invalid. It might be removed", + "5213970642134448962": { + "message": "Attempted to get home support flag of a display that does not exist: %d", "level": "WARN", "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1789603530": { - "message": "Removing activity %s hasSavedState=%b stateNotNeeded=%s finishing=%b state=%s callers=%s", + "-2065144681579661392": { + "message": "onPointerDownOutsideFocusLocked called on %s", "level": "INFO", - "group": "WM_DEBUG_ADD_REMOVE", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1794249572": { - "message": "Requesting StartTransition: %s", + "-7394143854567081754": { + "message": "grantEmbeddedWindowFocus win=%s dropped focus so setting focus to null since no candidate was found", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/TransitionController.java" - }, - "1804245629": { - "message": "Attempted to add starting window to token but already cleaned", - "level": "WARN", - "group": "WM_ERROR", + "group": "WM_DEBUG_FOCUS", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1805116444": { - "message": "We don't support remote animation for Task with multiple TaskFragmentOrganizers.", - "level": "ERROR", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" - }, - "1810019902": { - "message": "TRANSIT_FLAG_OPEN_BEHIND, adding %s to mOpeningApps", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "1810209625": { - "message": "Animation done in %s: exiting=%b, reportedVisible=%b", + "-6056928081282320632": { + "message": "grantEmbeddedWindowFocus win=%s grantFocus=%s", "level": "VERBOSE", - "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "1810872941": { - "message": "setWallpaperCropHints: non-existent wallpaper token: %s", + "6110791601270766802": { + "message": "TaskFragmentTransaction changes are not collected in transition because there is an ongoing sync for applySyncTransaction().", "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_WINDOW_TRANSITIONS", + "at": "com\/android\/server\/wm\/WindowOrganizerController.java" }, - "1820873642": { - "message": "SyncGroup %d: Unfinished dependencies: %s", + "9200403125156001641": { + "message": "Apply window transaction, syncId=%d", "level": "VERBOSE", - "group": "WM_DEBUG_SYNC_ENGINE", - "at": "com\/android\/server\/wm\/BLASTSyncEngine.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/WindowOrganizerController.java" }, - "1822314934": { - "message": "Expected target rootTask=%s to restored behind rootTask=%s but it is behind rootTask=%s", - "level": "WARN", - "group": "WM_DEBUG_RECENTS_ANIMATIONS", - "at": "com\/android\/server\/wm\/RecentsAnimation.java" + "433446585990132440": { + "message": "Set sync ready, syncId=%d", + "level": "VERBOSE", + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/WindowOrganizerController.java" }, - "1822843721": { - "message": "Aborted starting %s: startingData=%s", + "6552038620140878489": { + "message": "Transaction ready, syncId=%d", "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_WINDOW_ORGANIZER", + "at": "com\/android\/server\/wm\/WindowOrganizerController.java" }, - "1824105730": { - "message": "setLockTaskAuth: task=%s mLockTaskAuth=%s", - "level": "DEBUG", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/Task.java" + "-4629255026637000251": { + "message": "Sending to proc %s new config %s", + "level": "VERBOSE", + "group": "WM_DEBUG_CONFIGURATION", + "at": "com\/android\/server\/wm\/WindowProcessController.java" }, - "1829094918": { - "message": "onLockTaskPackagesUpdated: removing %s mLockTaskAuth()=%s", + "-7237767461056267619": { + "message": "%s: Setting back callback %s", "level": "DEBUG", - "group": "WM_DEBUG_LOCKTASK", - "at": "com\/android\/server\/wm\/LockTaskController.java" + "group": "WM_DEBUG_BACK_PREVIEW", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1831008694": { - "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/WindowContainer.java" + "8135615413833185273": { + "message": "Adding %s to %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1836214582": { - "message": "startingData was nulled out before handling mAddStartingWindow: %s", + "8842744325264128950": { + "message": "Resize reasons for w=%s: %s configChanged=%b didFrameInsetsChange=%b", "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_RESIZE", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1836306327": { - "message": "Skipping set freeze of %s", + "-8636590597069784069": { + "message": "Resizing window %s", + "level": "VERBOSE", + "group": "WM_DEBUG_RESIZE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-2710188685736986208": { + "message": "Orientation not waiting for draw in %s, surfaceController %s", "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1856783490": { - "message": "resumeTopActivity: Restarting %s", + "5236278969232209904": { + "message": "onMovedByResize: Moving %s", "level": "DEBUG", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_RESIZE", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1865125884": { - "message": "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, mScreenOnFully=%b, mKeyguardDrawComplete=%b, mWindowManagerDrawComplete=%b", + "7646042751617940718": { + "message": "Set animatingExit: reason=onAppVisibilityChanged win=%s", "level": "DEBUG", - "group": "WM_DEBUG_SCREEN_ON", - "at": "com\/android\/server\/wm\/DisplayPolicy.java" - }, - "1866772666": { - "message": "SAFE MODE not enabled", - "level": "INFO", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1874559932": { - "message": "The TaskDisplayArea with %s does not exist.", - "level": "WARN", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/DisplayAreaPolicyBuilder.java" + "1783521309242112490": { + "message": "onResize: Resizing %s", + "level": "DEBUG", + "group": "WM_DEBUG_RESIZE", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1877863087": { - "message": "Display id=%d is ignoring orientation request for %d, return %d", + "1351053513466395411": { + "message": "WS.removeImmediately: %s Already removed...", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1879463933": { - "message": "attachWindowContextToWindowToken: calling from non-existing process pid=%d uid=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "3927343382258792268": { + "message": "removeIfPossible: %s callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1891501279": { - "message": "cancelAnimation(): reason=%s", + "-4831815184899821371": { + "message": "Starting window removed %s", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1912291550": { - "message": "Sleep still waiting to pause %s", + "-5803097884846965819": { + "message": "Remove client=%x, surfaceController=%s Callers=%s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1918448345": { - "message": "Task appeared taskId=%d", + "-2547748024041128829": { + "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mDisplayFrozen=%b callers=%s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_ORGANIZER", - "at": "com\/android\/server\/wm\/TaskOrganizerController.java" - }, - "1928325128": { - "message": "Run showImeRunner", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1931178855": { - "message": "\tnonApp=%s", - "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "7789778354950913237": { + "message": "Set animatingExit: reason=remove\/applyAnimation win=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1945495497": { - "message": "Focused window didn't have a valid surface drawn.", - "level": "DEBUG", - "group": "WM_DEBUG_BACK_PREVIEW", - "at": "com\/android\/server\/wm\/BackNavigationController.java" + "-4143841388126586338": { + "message": "Not removing %s due to exit animation", + "level": "VERBOSE", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1946983717": { - "message": "Waiting for screen on due to %s", + "4419190702135590390": { + "message": "Set animatingExit: reason=remove\/isAnimating win=%s", "level": "VERBOSE", - "group": "WM_DEBUG_STATES", - "at": "com\/android\/server\/wm\/TaskFragment.java" + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1947239194": { - "message": "Deferring rotation, still finishing previous rotation", + "-6167820560758523840": { + "message": "setAnimationLocked: setting mFocusMayChange true", + "level": "INFO", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-208079497999140637": { + "message": "WindowState.hideLw: setting mFocusMayChange true", + "level": "INFO", + "group": "WM_DEBUG_FOCUS_LIGHT", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "8812513438749898553": { + "message": "set mOrientationChanging of %s", "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1947936538": { - "message": "Found matching class!", + "-2964267636425934067": { + "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b", + "level": "ERROR", + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "7336961102428192483": { + "message": "Clear animatingExit: reason=destroySurface win=%s", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1955470028": { - "message": "computeFractionRendered: visibleRegion=%s screenBounds=%s contentSize=%s scale=%f,%f", + "-6920306331987525705": { + "message": "Reporting new frame to %s: %s", "level": "VERBOSE", - "group": "WM_DEBUG_TPL", - "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java" + "group": "WM_DEBUG_RESIZE", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1964565370": { - "message": "Starting remote animation", + "2714651498627020992": { + "message": "Resizing %s WITH DRAW PENDING", "level": "INFO", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1967975839": { - "message": "Changing app %s visible=%b performLayout=%b", + "-5755338358883139945": { + "message": "Requested redraw for orientation change: %s", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1984782949": { - "message": ">>> OPEN TRANSACTION animate", - "level": "INFO", - "group": "WM_SHOW_TRANSACTIONS", - "at": "com\/android\/server\/wm\/WindowAnimator.java" + "-5211036212243647844": { + "message": "notifyInsetsChanged for %s ", + "level": "DEBUG", + "group": "WM_DEBUG_WINDOW_INSETS", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1984843251": { - "message": "Hiding wallpaper %s from %s target=%s prev=%s callers=%s", + "-3186229270467822891": { + "message": "notifyInsetsControlChanged for %s ", "level": "DEBUG", - "group": "WM_DEBUG_WALLPAPER", - "at": "com\/android\/server\/wm\/WallpaperController.java" + "group": "WM_DEBUG_WINDOW_INSETS", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1995093920": { - "message": "Checking to restart %s: changed=0x%s, handles=0x%s, mLastReportedConfiguration=%s", + "-7413136364930452718": { + "message": "performShowLocked: mDrawState=HAS_DRAWN in %s", "level": "VERBOSE", - "group": "WM_DEBUG_CONFIGURATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "1999594750": { - "message": "startAnimation", + "7624470121297688739": { + "message": "shouldWaitAnimatingExit: isTransition: %s", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "2001473656": { - "message": "App %s is focused, but the window is not ready. Start a transaction to remove focus from the window of non-focused apps.", - "level": "VERBOSE", - "group": "WM_DEBUG_FOCUS_LIGHT", - "at": "com\/android\/server\/wm\/InputMonitor.java" + "810267895099109466": { + "message": "shouldWaitAnimatingExit: isAnimating: %s", + "level": "DEBUG", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "2004282287": { - "message": "Override sync-method for %s because seamless rotating", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "-1760879391350377377": { + "message": "shouldWaitAnimatingExit: isWallpaperTarget: %s", + "level": "DEBUG", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "2010476671": { - "message": "Animation done in %s: reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b", + "272960397873328729": { + "message": "Clear window stuck on animatingExit status: %s", + "level": "WARN", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/WindowState.java" + }, + "-1007526574020149845": { + "message": "onExitAnimationDone in %s: exiting=%b remove=%b selfAnimating=%b anim=%s", "level": "VERBOSE", "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/ActivityRecord.java" + "at": "com\/android\/server\/wm\/WindowState.java" }, - "2018454757": { - "message": "WS.removeImmediately: %s Already removed...", + "1738645946553610841": { + "message": "Exit animation finished in %s: remove=%b", "level": "VERBOSE", "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/WindowState.java" }, - "2018852077": { - "message": "Creating SplashScreenStartingData", - "level": "VERBOSE", - "group": "WM_DEBUG_STARTING_WINDOW", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, - "2019765997": { - "message": "selectRotationAnimation topFullscreen=%s rotationAnimation=%d forceJumpcut=%b", - "level": "INFO", + "-7737516306844862315": { + "message": "Clear animatingExit: reason=exitAnimationDone win=%s", + "level": "DEBUG", "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, - "2021079047": { - "message": "%s", - "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN", - "at": "com\/android\/server\/wm\/TransitionController.java" + "at": "com\/android\/server\/wm\/WindowState.java" }, - "2022422429": { - "message": "createAnimationAdapter(): container=%s", + "-3153130647145726082": { + "message": "Clear animatingExit: reason=clearAnimatingFlags win=%s", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/RemoteAnimationController.java" + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "2024493888": { - "message": "\tWallpaper of display=%s is not visible", + "-5202247309108694583": { + "message": "Clear animatingExit: reason=relayoutVisibleWindow win=%s", "level": "DEBUG", - "group": "WM_DEBUG_REMOTE_ANIMATIONS", - "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java" + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "2028163120": { - "message": "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s isEntrance=%s Callers=%s", + "6291563604478341956": { + "message": "Setting move animation on %s", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "2034780299": { - "message": "CHECK_IF_BOOT_ANIMATION_FINISHED:", - "level": "INFO", - "group": "WM_DEBUG_BOOT", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-5774445199273871848": { + "message": "Preparing to sync a window that was already in the sync, so try dropping buffer. win=%s", + "level": "DEBUG", + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "2039056415": { - "message": "Found matching affinity candidate!", + "8097934579596343476": { + "message": "Got a buffer for request id=%d but latest request is id=%d. Since the buffer is out-of-date, drop it. win=%s", "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/RootWindowContainer.java" + "group": "WM_DEBUG_SYNC_ENGINE", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "2043434284": { - "message": "setWallpaperShowWhenLocked: non-existent wallpaper token: %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "8269653477215188641": { + "message": "SURFACE isSecure=%b: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowState.java" }, - "2045641491": { - "message": "Checking %d opening apps (frozen=%b timeout=%b)...", + "-1495677286613044867": { + "message": "Animation done in %s: exiting=%b, reportedVisible=%b", "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "2053743391": { - "message": " Add condition %s for #%d", + "3436877176443058520": { + "message": "Finishing drawing window %s: mDrawState=%s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "2060978050": { - "message": "moveWindowTokenToDisplay: Attempted to move token: %s to non-exiting displayId=%d", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "345647873457403698": { + "message": "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s", + "level": "VERBOSE", + "group": "WM_DEBUG_DRAW", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "2066210760": { - "message": "foldStateChanged: displayId %d, halfFoldStateChanged %s, saved rotation: %d, mUserRotation: %d, mLastSensorRotation: %d, mLastOrientation: %d, mRotation: %d", + "-2385558637577093121": { + "message": "Draw state now committed in %s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "group": "WM_DEBUG_STARTING_WINDOW", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "2070726247": { - "message": "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s", - "level": "DEBUG", - "group": "WM_DEBUG_WINDOW_INSETS", - "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" + "-3490933626936411542": { + "message": "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s", + "level": "INFO", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "2075693141": { - "message": "Set animatingExit: reason=startExitingAnimation\/%s win=%s", - "level": "DEBUG", + "-6088246515441976339": { + "message": "createSurface %s: mDrawState=DRAW_PENDING", + "level": "INFO", "group": "WM_DEBUG_ANIM", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "2079410261": { - "message": "applyAnimation: override requested, but it is prohibited by policy.", - "level": "ERROR", - "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", - "at": "com\/android\/server\/wm\/AppTransition.java" + "2353125758087345363": { + "message": " CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "2083556954": { - "message": "Set mOrientationChanging of %s", + "-4491856282178275074": { + "message": "SURFACE DESTROY: %s. %s", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "8602950884833508970": { + "message": "Orientation change skips hidden %s", "level": "VERBOSE", "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "2086878461": { - "message": "Could not send command %s with parameters %s. %s", - "level": "WARN", - "group": "WM_ERROR", - "at": "com\/android\/server\/wm\/WindowManagerService.java" + "-5079712802591263622": { + "message": "SURFACE controller=%s alpha=%f HScale=%f, VScale=%f: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "2100457473": { - "message": "Task=%d contains embedded TaskFragment. Disabled all input during TaskFragment remote animation.", - "level": "DEBUG", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/AppTransitionController.java" + "-2824875917893878016": { + "message": "Orientation continue waiting for draw in %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "2117696413": { - "message": "moveTaskToFront: moving taskId=%d", - "level": "DEBUG", - "group": "WM_DEBUG_TASKS", - "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java" + "7457181879495900576": { + "message": "Orientation change complete in %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" }, - "2119122320": { - "message": "setInputMethodTarget %s", + "-5668794009329913533": { + "message": "applyAnimation: win=%s anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ANIM", + "at": "com\/android\/server\/wm\/WindowStateAnimator.java" + }, + "-2055407587764455051": { + "message": "SURFACE HIDE ( %s ): %s", "level": "INFO", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/DisplayContent.java" + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" }, - "2124732293": { - "message": "#%d: Met condition: %s", + "-5854683348829455340": { + "message": "Destroying surface %s called by %s", + "level": "INFO", + "group": "WM_SHOW_SURFACE_ALLOC", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "7813672046338784579": { + "message": "SURFACE isOpaque=%b: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "-8864150640874799238": { + "message": "SURFACE isColorSpaceAgnostic=%b: %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "-8398940245851553814": { + "message": "SURFACE SHOW (performLayout): %s", + "level": "INFO", + "group": "WM_SHOW_TRANSACTIONS", + "at": "com\/android\/server\/wm\/WindowSurfaceController.java" + }, + "8174298531248485625": { + "message": "removeAllWindowsIfPossible: removing win=%s", + "level": "WARN", + "group": "WM_DEBUG_WINDOW_MOVEMENT", + "at": "com\/android\/server\/wm\/WindowToken.java" + }, + "2740931087734487464": { + "message": "addWindow: win=%s Callers=%s", + "level": "DEBUG", + "group": "WM_DEBUG_FOCUS", + "at": "com\/android\/server\/wm\/WindowToken.java" + }, + "2382798629637143561": { + "message": "Adding %s to %s", "level": "VERBOSE", - "group": "WM_DEBUG_WINDOW_TRANSITIONS", - "at": "com\/android\/server\/wm\/Transition.java" + "group": "WM_DEBUG_ADD_REMOVE", + "at": "com\/android\/server\/wm\/WindowToken.java" }, - "2128917433": { - "message": "onProposedRotationChanged, rotation=%d", + "-7314975896738778749": { + "message": "setClientVisible: %s clientVisible=%b Callers=%s", "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/WindowToken.java" } }, "groups": { diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 11b827117aa3..bd9abec22325 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -21,12 +21,14 @@ import android.os.Build; import android.os.StrictMode; /** - * @hide This should not be made public in its present form because it - * assumes that private and secret key bytes are available and would - * preclude the use of hardware crypto. + * This class provides some constants and helper methods related to Android's Keystore service. + * This class was originally much larger, but its functionality was superseded by other classes. + * It now just contains a few remaining pieces for which the users haven't been updated yet. + * You may be looking for {@link java.security.KeyStore} instead. + * + * @hide */ public class KeyStore { - private static final String TAG = "KeyStore"; // ResponseCodes - see system/security/keystore/include/keystore/keystore.h @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -42,50 +44,6 @@ public class KeyStore { return KEY_STORE; } - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public byte[] get(String key) { - return null; - } - - /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public boolean delete(String key) { - return false; - } - - /** - * List uids of all keys that are auth bound to the current user. - * Only system is allowed to call this method. - * @hide - * @deprecated This function always returns null. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public int[] listUidsOfAuthBoundKeys() { - return null; - } - - - /** - * @hide - * @deprecated This function has no effect. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public boolean unlock(String password) { - return false; - } - - /** - * - * @return - * @deprecated This function always returns true. - * @hide - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - public boolean isEmpty() { - return true; - } - /** * Add an authentication record to the keystore authorization table. * @@ -105,13 +63,4 @@ public class KeyStore { public void onDeviceOffBody() { AndroidKeyStoreMaintenance.onDeviceOffBody(); } - - /** - * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error - * code. - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static KeyStoreException getKeyStoreException(int errorCode) { - return new KeyStoreException(-10000, "Should not be called."); - } } diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java index f50efd2c3328..5cffe46936a2 100644 --- a/keystore/java/android/security/keystore/KeyInfo.java +++ b/keystore/java/android/security/keystore/KeyInfo.java @@ -16,6 +16,7 @@ package android.security.keystore; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; @@ -81,6 +82,7 @@ public class KeyInfo implements KeySpec { private final @KeyProperties.AuthEnum int mUserAuthenticationType; private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware; private final boolean mUserAuthenticationValidWhileOnBody; + private final boolean mUnlockedDeviceRequired; private final boolean mTrustedUserPresenceRequired; private final boolean mInvalidatedByBiometricEnrollment; private final boolean mUserConfirmationRequired; @@ -107,6 +109,7 @@ public class KeyInfo implements KeySpec { @KeyProperties.AuthEnum int userAuthenticationType, boolean userAuthenticationRequirementEnforcedBySecureHardware, boolean userAuthenticationValidWhileOnBody, + boolean unlockedDeviceRequired, boolean trustedUserPresenceRequired, boolean invalidatedByBiometricEnrollment, boolean userConfirmationRequired, @@ -132,6 +135,7 @@ public class KeyInfo implements KeySpec { mUserAuthenticationRequirementEnforcedBySecureHardware = userAuthenticationRequirementEnforcedBySecureHardware; mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody; + mUnlockedDeviceRequired = unlockedDeviceRequired; mTrustedUserPresenceRequired = trustedUserPresenceRequired; mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment; mUserConfirmationRequired = userConfirmationRequired; @@ -275,6 +279,20 @@ public class KeyInfo implements KeySpec { } /** + * Returns {@code true} if the key is authorized to be used only when the device is unlocked. + * + * <p>This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. + * + * @see KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean) + * @see KeyProtection.Builder#setUnlockedDeviceRequired(boolean) + */ + @FlaggedApi(android.security.Flags.FLAG_KEYINFO_UNLOCKED_DEVICE_REQUIRED) + public boolean isUnlockedDeviceRequired() { + return mUnlockedDeviceRequired; + } + + /** * Returns {@code true} if the key is authorized to be used only for messages confirmed by the * user. * diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java index 97592b44ba2e..2682eb657963 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java @@ -93,6 +93,7 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { long userAuthenticationValidityDurationSeconds = 0; boolean userAuthenticationRequired = true; boolean userAuthenticationValidWhileOnBody = false; + boolean unlockedDeviceRequired = false; boolean trustedUserPresenceRequired = false; boolean trustedUserConfirmationRequired = false; int remainingUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT; @@ -184,6 +185,9 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { + userAuthenticationValidityDurationSeconds + " seconds"); } break; + case KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED: + unlockedDeviceRequired = true; + break; case KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY: userAuthenticationValidWhileOnBody = KeyStore2ParameterUtils.isSecureHardware(a.securityLevel); @@ -257,6 +261,7 @@ public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi { : keymasterSwEnforcedUserAuthenticators, userAuthenticationRequirementEnforcedBySecureHardware, userAuthenticationValidWhileOnBody, + unlockedDeviceRequired, trustedUserPresenceRequired, invalidatedByBiometricEnrollment, trustedUserConfirmationRequired, diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java index 65955b1d9bcc..e37dea4dfd69 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java @@ -126,7 +126,7 @@ public final class CommonFoldingFeature { * @see #FEATURE_PATTERN * @return {@link List} of {@link CommonFoldingFeature}. */ - static List<CommonFoldingFeature> parseListFromString(@NonNull String value, + public static List<CommonFoldingFeature> parseListFromString(@NonNull String value, @State int hingeState) { List<CommonFoldingFeature> features = new ArrayList<>(); String[] featureStrings = value.split(";"); diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java index a184dff5005b..88fd461debbe 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java @@ -36,6 +36,7 @@ import androidx.window.util.BaseDataProducer; import com.android.internal.R; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -78,7 +79,9 @@ public final class DeviceStateManagerFoldingFeatureProducer private int mCurrentBaseDeviceState = INVALID_DEVICE_STATE; @NonNull - private final BaseDataProducer<String> mRawFoldSupplier; + private final RawFoldingFeatureProducer mRawFoldSupplier; + + private final boolean mIsHalfOpenedSupported; private final DeviceStateCallback mDeviceStateCallback = new DeviceStateCallback() { @Override @@ -101,10 +104,12 @@ public final class DeviceStateManagerFoldingFeatureProducer }; public DeviceStateManagerFoldingFeatureProducer(@NonNull Context context, - @NonNull BaseDataProducer<String> rawFoldSupplier) { + @NonNull RawFoldingFeatureProducer rawFoldSupplier, + @NonNull DeviceStateManager deviceStateManager) { mRawFoldSupplier = rawFoldSupplier; String[] deviceStatePosturePairs = context.getResources() .getStringArray(R.array.config_device_state_postures); + boolean isHalfOpenedSupported = false; for (String deviceStatePosturePair : deviceStatePosturePairs) { String[] deviceStatePostureMapping = deviceStatePosturePair.split(":"); if (deviceStatePostureMapping.length != 2) { @@ -128,12 +133,13 @@ public final class DeviceStateManagerFoldingFeatureProducer } continue; } - + isHalfOpenedSupported = isHalfOpenedSupported + || posture == CommonFoldingFeature.COMMON_STATE_HALF_OPENED; mDeviceStateToPostureMap.put(deviceState, posture); } - + mIsHalfOpenedSupported = isHalfOpenedSupported; if (mDeviceStateToPostureMap.size() > 0) { - Objects.requireNonNull(context.getSystemService(DeviceStateManager.class)) + Objects.requireNonNull(deviceStateManager) .registerCallback(context.getMainExecutor(), mDeviceStateCallback); } } @@ -188,6 +194,31 @@ public final class DeviceStateManagerFoldingFeatureProducer } /** + * Returns a {@link List} of all the {@link CommonFoldingFeature} with the state set to + * {@link CommonFoldingFeature#COMMON_STATE_UNKNOWN}. This method parses a {@link String} so a + * caller should consider caching the value or the derived value. + */ + @NonNull + public List<CommonFoldingFeature> getFoldsWithUnknownState() { + Optional<String> optionalFoldingFeatureString = mRawFoldSupplier.getCurrentData(); + + if (optionalFoldingFeatureString.isPresent()) { + return CommonFoldingFeature.parseListFromString( + optionalFoldingFeatureString.get(), CommonFoldingFeature.COMMON_STATE_UNKNOWN + ); + } + return Collections.emptyList(); + } + + + /** + * Returns {@code true} if the device supports half-opened mode, {@code false} otherwise. + */ + public boolean isHalfOpenedSupported() { + return mIsHalfOpenedSupported; + } + + /** * Adds the data to the storeFeaturesConsumer when the data is ready. * @param storeFeaturesConsumer a consumer to collect the data when it is first available. */ diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java index 29cf05407a61..6714263ad952 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java @@ -20,6 +20,7 @@ import android.app.ActivityTaskManager; import android.app.ActivityThread; import android.app.Application; import android.content.Context; +import android.hardware.devicestate.DeviceStateManager; import android.util.Log; import androidx.annotation.NonNull; @@ -64,6 +65,11 @@ public class WindowExtensionsImpl implements WindowExtensions { } @NonNull + private DeviceStateManager getDeviceStateManager() { + return Objects.requireNonNull(getApplication().getSystemService(DeviceStateManager.class)); + } + + @NonNull private DeviceStateManagerFoldingFeatureProducer getFoldingFeatureProducer() { if (mFoldingFeatureProducer == null) { synchronized (mLock) { @@ -73,7 +79,7 @@ public class WindowExtensionsImpl implements WindowExtensions { new RawFoldingFeatureProducer(context); mFoldingFeatureProducer = new DeviceStateManagerFoldingFeatureProducer(context, - foldingFeatureProducer); + foldingFeatureProducer, getDeviceStateManager()); } } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index b2e5b75cf0b5..ae3a854baf9f 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -72,6 +72,7 @@ import android.util.Pair; import android.util.Size; import android.util.SparseArray; import android.view.WindowMetrics; +import android.window.ActivityWindowInfo; import android.window.TaskFragmentAnimationParams; import android.window.TaskFragmentInfo; import android.window.TaskFragmentOperation; @@ -2864,11 +2865,27 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen */ @Override public boolean isActivityEmbedded(@NonNull Activity activity) { + Objects.requireNonNull(activity); synchronized (mLock) { + if (Flags.activityWindowInfoFlag()) { + final ActivityWindowInfo activityWindowInfo = getActivityWindowInfo(activity); + return activityWindowInfo != null && activityWindowInfo.isEmbedded(); + } return mPresenter.isActivityEmbedded(activity.getActivityToken()); } } + @Nullable + private static ActivityWindowInfo getActivityWindowInfo(@NonNull Activity activity) { + if (activity.isFinishing()) { + return null; + } + final ActivityThread.ActivityClientRecord record = + ActivityThread.currentActivityThread() + .getActivityClient(activity.getActivityToken()); + return record != null ? record.getActivityWindowInfo() : null; + } + /** * If the two rules have the same presentation, and the calculated {@link SplitAttributes} * matches the {@link SplitAttributes} of {@link SplitContainer}, we can reuse the same diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/DisplayFoldFeatureUtil.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/DisplayFoldFeatureUtil.java new file mode 100644 index 000000000000..a0f481a911ad --- /dev/null +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/DisplayFoldFeatureUtil.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.window.extensions.layout; + +import androidx.window.common.CommonFoldingFeature; +import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; + +import java.util.ArrayList; +import java.util.List; + +/** + * Util functions for working with {@link androidx.window.extensions.layout.DisplayFoldFeature}. + */ +public class DisplayFoldFeatureUtil { + + private DisplayFoldFeatureUtil() {} + + private static DisplayFoldFeature create(CommonFoldingFeature foldingFeature, + boolean isHalfOpenedSupported) { + final int foldType; + if (foldingFeature.getType() == CommonFoldingFeature.COMMON_TYPE_HINGE) { + foldType = DisplayFoldFeature.TYPE_HINGE; + } else { + foldType = DisplayFoldFeature.TYPE_SCREEN_FOLD_IN; + } + DisplayFoldFeature.Builder featureBuilder = new DisplayFoldFeature.Builder(foldType); + + if (isHalfOpenedSupported) { + featureBuilder.addProperty(DisplayFoldFeature.FOLD_PROPERTY_SUPPORTS_HALF_OPENED); + } + return featureBuilder.build(); + } + + /** + * Returns the list of supported {@link DisplayFeature} calculated from the + * {@link DeviceStateManagerFoldingFeatureProducer}. + */ + public static List<DisplayFoldFeature> extractDisplayFoldFeatures( + DeviceStateManagerFoldingFeatureProducer producer) { + List<DisplayFoldFeature> foldFeatures = new ArrayList<>(); + List<CommonFoldingFeature> folds = producer.getFoldsWithUnknownState(); + + final boolean isHalfOpenedSupported = producer.isHalfOpenedSupported(); + for (CommonFoldingFeature fold : folds) { + foldFeatures.add(DisplayFoldFeatureUtil.create(fold, isHalfOpenedSupported)); + } + return foldFeatures; + } +} diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java index 6e704f35fb22..4fd11c495529 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java @@ -45,7 +45,6 @@ import androidx.window.common.CommonFoldingFeature; import androidx.window.common.DeviceStateManagerFoldingFeatureProducer; import androidx.window.common.EmptyLifecycleCallbacksAdapter; import androidx.window.extensions.core.util.function.Consumer; -import androidx.window.util.DataProducer; import java.util.ArrayList; import java.util.Collections; @@ -56,10 +55,6 @@ import java.util.Set; /** * Reference implementation of androidx.window.extensions.layout OEM interface for use with * WindowManager Jetpack. - * - * NOTE: This version is a work in progress and under active development. It MUST NOT be used in - * production builds since the interface can still change before reaching stable version. - * Please refer to {@link androidx.window.sidecar.SampleSidecarImpl} instead. */ public class WindowLayoutComponentImpl implements WindowLayoutComponent { private static final String TAG = WindowLayoutComponentImpl.class.getSimpleName(); @@ -71,7 +66,7 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { new ArrayMap<>(); @GuardedBy("mLock") - private final DataProducer<List<CommonFoldingFeature>> mFoldingFeatureProducer; + private final DeviceStateManagerFoldingFeatureProducer mFoldingFeatureProducer; @GuardedBy("mLock") private final List<CommonFoldingFeature> mLastReportedFoldingFeatures = new ArrayList<>(); @@ -87,12 +82,17 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { private final RawConfigurationChangedListener mRawConfigurationChangedListener = new RawConfigurationChangedListener(); + private final SupportedWindowFeatures mSupportedWindowFeatures; + public WindowLayoutComponentImpl(@NonNull Context context, @NonNull DeviceStateManagerFoldingFeatureProducer foldingFeatureProducer) { ((Application) context.getApplicationContext()) .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged()); mFoldingFeatureProducer = foldingFeatureProducer; mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged); + final List<DisplayFoldFeature> displayFoldFeatures = + DisplayFoldFeatureUtil.extractDisplayFoldFeatures(mFoldingFeatureProducer); + mSupportedWindowFeatures = new SupportedWindowFeatures.Builder(displayFoldFeatures).build(); } /** @@ -283,6 +283,15 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent { } } + /** + * Returns the {@link SupportedWindowFeatures} for the device. This list does not change over + * time. + */ + @NonNull + public SupportedWindowFeatures getSupportedWindowFeatures() { + return mSupportedWindowFeatures; + } + /** @see #getWindowLayoutInfo(Context, List) */ private WindowLayoutInfo getWindowLayoutInfo(int displayId, @NonNull WindowConfiguration windowConfiguration, diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java index a836e05b2d66..56c3bce87d6e 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java @@ -17,6 +17,7 @@ package androidx.window.sidecar; import static android.view.Display.DEFAULT_DISPLAY; + import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation; import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect; @@ -25,6 +26,7 @@ import android.app.ActivityThread; import android.app.Application; import android.content.Context; import android.graphics.Rect; +import android.hardware.devicestate.DeviceStateManager; import android.os.Bundle; import android.os.IBinder; @@ -49,10 +51,11 @@ class SampleSidecarImpl extends StubSidecar { SampleSidecarImpl(Context context) { ((Application) context.getApplicationContext()) .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged()); - BaseDataProducer<String> settingsFeatureProducer = new RawFoldingFeatureProducer(context); + RawFoldingFeatureProducer settingsFeatureProducer = new RawFoldingFeatureProducer(context); BaseDataProducer<List<CommonFoldingFeature>> foldingFeatureProducer = new DeviceStateManagerFoldingFeatureProducer(context, - settingsFeatureProducer); + settingsFeatureProducer, + context.getSystemService(DeviceStateManager.class)); foldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged); } diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp index d66c925de376..0ecf1f8f1feb 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -82,16 +82,18 @@ filegroup { genrule { name: "wm_shell_protolog_src", srcs: [ + ":protolog-impl", ":wm_shell_protolog-groups", ":wm_shell-sources", ], tools: ["protologtool"], cmd: "$(location protologtool) transform-protolog-calls " + "--protolog-class com.android.internal.protolog.common.ProtoLog " + - "--protolog-impl-class com.android.wm.shell.protolog.ShellProtoLogImpl " + - "--protolog-cache-class com.android.wm.shell.protolog.ShellProtoLogCache " + "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + "--loggroups-jar $(location :wm_shell_protolog-groups) " + + "--viewer-config-file-path /system_ext/etc/wmshell.protolog.pb " + + "--legacy-viewer-config-file-path /system_ext/etc/wmshell.protolog.json.gz " + + "--legacy-output-file-path /data/misc/wmtrace/shell_log.winscope " + "--output-srcjar $(out) " + "$(locations :wm_shell-sources)", out: ["wm_shell_protolog.srcjar"], @@ -108,12 +110,30 @@ genrule { "--protolog-class com.android.internal.protolog.common.ProtoLog " + "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + "--loggroups-jar $(location :wm_shell_protolog-groups) " + - "--viewer-conf $(out) " + + "--viewer-config-type json " + + "--viewer-config $(out) " + "$(locations :wm_shell-sources)", out: ["wm_shell_protolog.json"], } genrule { + name: "gen-wmshell.protolog.pb", + srcs: [ + ":wm_shell_protolog-groups", + ":wm_shell-sources", + ], + tools: ["protologtool"], + cmd: "$(location protologtool) generate-viewer-config " + + "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + + "--loggroups-jar $(location :wm_shell_protolog-groups) " + + "--viewer-config-type proto " + + "--viewer-config $(out) " + + "$(locations :wm_shell-sources)", + out: ["wmshell.protolog.pb"], +} + +genrule { name: "protolog.json.gz", srcs: [":generate-wm_shell_protolog.json"], out: ["wmshell.protolog.json.gz"], @@ -127,6 +147,13 @@ prebuilt_etc { filename_from_src: true, } +prebuilt_etc { + name: "wmshell.protolog.pb", + system_ext_specific: true, + src: ":gen-wmshell.protolog.pb", + filename_from_src: true, +} + // End ProtoLog java_library { diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig index 0967f4e83c74..b61dda4c4e53 100644 --- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig +++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig @@ -8,14 +8,6 @@ flag { } flag { - name: "enable_desktop_windowing" - namespace: "multitasking" - description: "Enables desktop windowing" - bug: "304778354" - is_fixed_read_only: true -} - -flag { name: "enable_split_contextual" namespace: "multitasking" description: "Enables invoking split contextually" diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml index d1b1af3e77ab..490f0883fbfb 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml @@ -16,6 +16,7 @@ --> <com.android.wm.shell.windowdecor.WindowDecorLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/desktop_mode_caption" android:layout_width="match_parent" @@ -27,6 +28,8 @@ android:id="@+id/open_menu_button" android:layout_width="wrap_content" android:layout_height="match_parent" + android:tint="?androidprv:attr/materialColorOnSurface" + android:background="?android:selectableItemBackground" android:orientation="horizontal" android:clickable="true" android:focusable="true" @@ -78,7 +81,9 @@ android:id="@+id/maximize_button_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="end"/> + android:layout_gravity="end" + android:clickable="true" + android:focusable="true" /> <ImageButton android:id="@+id/close_window" @@ -86,9 +91,10 @@ android:layout_height="40dp" android:padding="4dp" android:layout_marginEnd="8dp" + android:tint="?androidprv:attr/materialColorOnSurface" + android:background="?android:selectableItemBackgroundBorderless" android:contentDescription="@string/close_button_text" android:src="@drawable/decor_close_button_dark" android:scaleType="fitCenter" - android:gravity="end" - android:background="@null"/> + android:gravity="end"/> </com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml index bb6efcec1a70..e0057fe64fd2 100644 --- a/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml +++ b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml @@ -14,7 +14,8 @@ ~ limitations under the License. --> -<merge xmlns:android="http://schemas.android.com/apk/res/android"> +<merge xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <ProgressBar android:id="@+id/progress_bar" style="?android:attr/progressBarStyleHorizontal" @@ -30,7 +31,8 @@ android:layout_height="40dp" android:padding="9dp" android:contentDescription="@string/maximize_button_text" + android:tint="?androidprv:attr/materialColorOnSurface" + android:background="?android:selectableItemBackgroundBorderless" android:src="@drawable/decor_desktop_mode_maximize_button_dark" - android:scaleType="fitCenter" - android:background="@drawable/rounded_button"/> + android:scaleType="fitCenter" /> </merge>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index cbfa74e9332b..48e6428524ae 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -101,6 +101,10 @@ <dimen name="split_divider_bar_width">10dp</dimen> <dimen name="split_divider_corner_size">42dp</dimen> + <!-- The distance from the edge of the screen to invoke splitscreen when the user is dragging + an intent that can be launched into split. --> + <dimen name="drag_launchable_intent_edge_margin">48dp</dimen> + <!-- One-Handed Mode --> <!-- Threshold for dragging distance to enable one-handed mode --> <dimen name="gestures_onehanded_drag_threshold">20dp</dimen> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java index 88525aabe53b..93893e33d2d5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java @@ -16,7 +16,10 @@ package com.android.wm.shell; -import com.android.wm.shell.protolog.ShellProtoLogImpl; +import com.android.internal.protolog.LegacyProtoLogImpl; +import com.android.internal.protolog.common.ILogger; +import com.android.internal.protolog.common.IProtoLog; +import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellInit; @@ -24,19 +27,19 @@ import java.io.PrintWriter; import java.util.Arrays; /** - * Controls the {@link ShellProtoLogImpl} in WMShell via adb shell commands. + * Controls the {@link ProtoLog} in WMShell via adb shell commands. * * Use with {@code adb shell dumpsys activity service SystemUIService WMShell protolog ...}. */ public class ProtoLogController implements ShellCommandHandler.ShellCommandActionHandler { private final ShellCommandHandler mShellCommandHandler; - private final ShellProtoLogImpl mShellProtoLog; + private final IProtoLog mShellProtoLog; public ProtoLogController(ShellInit shellInit, ShellCommandHandler shellCommandHandler) { shellInit.addInitCallback(this::onInit, this); mShellCommandHandler = shellCommandHandler; - mShellProtoLog = ShellProtoLogImpl.getSingleInstance(); + mShellProtoLog = ProtoLog.getSingleInstance(); } void onInit() { @@ -45,22 +48,35 @@ public class ProtoLogController implements ShellCommandHandler.ShellCommandActio @Override public boolean onShellCommand(String[] args, PrintWriter pw) { + final ILogger logger = pw::println; switch (args[0]) { case "status": { - pw.println(mShellProtoLog.getStatus()); + if (android.tracing.Flags.perfettoProtolog()) { + pw.println("(Deprecated) legacy command. Use Perfetto commands instead."); + return false; + } + ((LegacyProtoLogImpl) mShellProtoLog).getStatus(); return true; } case "start": { - mShellProtoLog.startProtoLog(pw); + if (android.tracing.Flags.perfettoProtolog()) { + pw.println("(Deprecated) legacy command. Use Perfetto commands instead."); + return false; + } + ((LegacyProtoLogImpl) mShellProtoLog).startProtoLog(pw); return true; } case "stop": { - mShellProtoLog.stopProtoLog(pw, true /* writeToFile */); + if (android.tracing.Flags.perfettoProtolog()) { + pw.println("(Deprecated) legacy command. Use Perfetto commands instead."); + return false; + } + ((LegacyProtoLogImpl) mShellProtoLog).stopProtoLog(pw, true); return true; } case "enable-text": { String[] groups = Arrays.copyOfRange(args, 1, args.length); - int result = mShellProtoLog.startTextLogging(groups, pw); + int result = mShellProtoLog.startLoggingToLogcat(groups, logger); if (result == 0) { pw.println("Starting logging on groups: " + Arrays.toString(groups)); return true; @@ -69,7 +85,7 @@ public class ProtoLogController implements ShellCommandHandler.ShellCommandActio } case "disable-text": { String[] groups = Arrays.copyOfRange(args, 1, args.length); - int result = mShellProtoLog.stopTextLogging(groups, pw); + int result = mShellProtoLog.stopLoggingToLogcat(groups, logger); if (result == 0) { pw.println("Stopping logging on groups: " + Arrays.toString(groups)); return true; @@ -78,19 +94,23 @@ public class ProtoLogController implements ShellCommandHandler.ShellCommandActio } case "enable": { String[] groups = Arrays.copyOfRange(args, 1, args.length); - return mShellProtoLog.startTextLogging(groups, pw) == 0; + return mShellProtoLog.startLoggingToLogcat(groups, logger) == 0; } case "disable": { String[] groups = Arrays.copyOfRange(args, 1, args.length); - return mShellProtoLog.stopTextLogging(groups, pw) == 0; + return mShellProtoLog.stopLoggingToLogcat(groups, logger) == 0; } case "save-for-bugreport": { + if (android.tracing.Flags.perfettoProtolog()) { + pw.println("(Deprecated) legacy command"); + return false; + } if (!mShellProtoLog.isProtoEnabled()) { pw.println("Logging to proto is not enabled for WMShell."); return false; } - mShellProtoLog.stopProtoLog(pw, true /* writeToFile */); - mShellProtoLog.startProtoLog(pw); + ((LegacyProtoLogImpl) mShellProtoLog).stopProtoLog(pw, true /* writeToFile */); + ((LegacyProtoLogImpl) mShellProtoLog).startProtoLog(pw); return true; } default: { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 15350fb19209..96aaf02cb5e3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -1799,11 +1799,12 @@ public class BubbleController implements ConfigurationChangeListener, @Override public void removeBubble(Bubble removedBubble) { if (mLayerView != null) { - mLayerView.removeBubble(removedBubble); - if (!mBubbleData.hasBubbles() && !isStackExpanded()) { - mLayerView.setVisibility(INVISIBLE); - removeFromWindowManagerMaybe(); - } + mLayerView.removeBubble(removedBubble, () -> { + if (!mBubbleData.hasBubbles() && !isStackExpanded()) { + mLayerView.setVisibility(INVISIBLE); + removeFromWindowManagerMaybe(); + } + }); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java index 78a41f759d96..42799d975e1b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java @@ -242,13 +242,17 @@ public class BubbleBarLayerView extends FrameLayout } /** Removes the given {@code bubble}. */ - public void removeBubble(Bubble bubble) { + public void removeBubble(Bubble bubble, Runnable endAction) { + Runnable cleanUp = () -> { + bubble.cleanupViews(); + endAction.run(); + }; if (mBubbleData.getBubbles().isEmpty()) { // we're removing the last bubble. collapse the expanded view and cleanup bubble views // at the end. - collapse(bubble::cleanupViews); + collapse(cleanUp); } else { - bubble.cleanupViews(); + cleanUp.run(); } } @@ -264,6 +268,9 @@ public class BubbleBarLayerView extends FrameLayout */ public void collapse(@Nullable Runnable endAction) { if (!mIsExpanded) { + if (endAction != null) { + endAction.run(); + } return; } mIsExpanded = false; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java index b57e2d2c6ac2..b87c2f6ebad5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java @@ -228,6 +228,14 @@ public class PipBoundsState { mExpandedMovementBounds.set(bounds); } + /** Updates the min and max sizes based on the size spec and aspect ratio. */ + public void updateMinMaxSize(float aspectRatio) { + final Size minSize = mSizeSpecSource.getMinSize(aspectRatio); + mMinSize.set(minSize.getWidth(), minSize.getHeight()); + final Size maxSize = mSizeSpecSource.getMaxSize(aspectRatio); + mMaxSize.set(maxSize.getWidth(), maxSize.getHeight()); + } + /** Sets the max possible size for resize. */ public void setMaxSize(int width, int height) { mMaxSize.set(width, height); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java index 8305fa6b0fbf..1071d728a56d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java @@ -51,4 +51,6 @@ public interface DesktopMode { /** Called when requested to go to desktop mode from the current focused app. */ void enterDesktop(int displayId); + /** Called when requested to go to fullscreen from the current focused desktop app. */ + void moveFocusedTaskToFullscreen(int displayId); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt new file mode 100644 index 000000000000..95d47146e834 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.desktopmode + +import com.android.internal.util.FrameworkStatsLog +import com.android.wm.shell.protolog.ShellProtoLogGroup +import com.android.wm.shell.util.KtProtoLog + +/** + * Event logger for logging desktop mode session events + */ +class DesktopModeEventLogger { + /** + * Logs the enter of desktop mode having session id [sessionId] and the reason [enterReason] for + * entering desktop mode + */ + fun logSessionEnter(sessionId: Int, enterReason: EnterReason) { + KtProtoLog.v( + ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, + "DesktopModeLogger: Logging session enter, session: %s reason: %s", + sessionId, enterReason.name + ) + FrameworkStatsLog.write(DESKTOP_MODE_ATOM_ID, + /* event */ FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__ENTER, + /* enterReason */ enterReason.reason, + /* exitReason */ 0, + /* session_id */ sessionId) + } + + /** + * Logs the exit of desktop mode having session id [sessionId] and the reason [exitReason] for + * exiting desktop mode + */ + fun logSessionExit(sessionId: Int, exitReason: ExitReason) { + KtProtoLog.v( + ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, + "DesktopModeLogger: Logging session exit, session: %s reason: %s", + sessionId, exitReason.name + ) + FrameworkStatsLog.write(DESKTOP_MODE_ATOM_ID, + /* event */ FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__EXIT, + /* enterReason */ 0, + /* exitReason */ exitReason.reason, + /* session_id */ sessionId) + } + + /** + * Logs that the task with update [taskUpdate] was added in the desktop mode session having + * session id [sessionId] + */ + fun logTaskAdded(sessionId: Int, taskUpdate: TaskUpdate) { + KtProtoLog.v( + ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, + "DesktopModeLogger: Logging task added, session: %s taskId: %s", + sessionId, taskUpdate.instanceId + ) + FrameworkStatsLog.write(DESKTOP_MODE_TASK_UPDATE_ATOM_ID, + /* task_event */ + FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_ADDED, + /* instance_id */ + taskUpdate.instanceId, + /* uid */ + taskUpdate.uid, + /* task_height */ + taskUpdate.taskHeight, + /* task_width */ + taskUpdate.taskWidth, + /* task_x */ + taskUpdate.taskX, + /* task_y */ + taskUpdate.taskY, + /* session_id */ + sessionId) + } + + /** + * Logs that the task with update [taskUpdate] was removed in the desktop mode session having + * session id [sessionId] + */ + fun logTaskRemoved(sessionId: Int, taskUpdate: TaskUpdate) { + KtProtoLog.v( + ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, + "DesktopModeLogger: Logging task remove, session: %s taskId: %s", + sessionId, taskUpdate.instanceId + ) + FrameworkStatsLog.write(DESKTOP_MODE_TASK_UPDATE_ATOM_ID, + /* task_event */ + FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_REMOVED, + /* instance_id */ + taskUpdate.instanceId, + /* uid */ + taskUpdate.uid, + /* task_height */ + taskUpdate.taskHeight, + /* task_width */ + taskUpdate.taskWidth, + /* task_x */ + taskUpdate.taskX, + /* task_y */ + taskUpdate.taskY, + /* session_id */ + sessionId) + } + + /** + * Logs that the task with update [taskUpdate] had it's info changed in the desktop mode session + * having session id [sessionId] + */ + fun logTaskInfoChanged(sessionId: Int, taskUpdate: TaskUpdate) { + KtProtoLog.v( + ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, + "DesktopModeLogger: Logging task info changed, session: %s taskId: %s", + sessionId, taskUpdate.instanceId + ) + FrameworkStatsLog.write(DESKTOP_MODE_TASK_UPDATE_ATOM_ID, + /* task_event */ + FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED, + /* instance_id */ + taskUpdate.instanceId, + /* uid */ + taskUpdate.uid, + /* task_height */ + taskUpdate.taskHeight, + /* task_width */ + taskUpdate.taskWidth, + /* task_x */ + taskUpdate.taskX, + /* task_y */ + taskUpdate.taskY, + /* session_id */ + sessionId) + } + + companion object { + data class TaskUpdate( + val instanceId: Int, + val uid: Int, + val taskHeight: Int = Int.MIN_VALUE, + val taskWidth: Int = Int.MIN_VALUE, + val taskX: Int = Int.MIN_VALUE, + val taskY: Int = Int.MIN_VALUE, + ) + + /** + * Enum EnterReason mapped to the EnterReason definition in + * stats/atoms/desktopmode/desktopmode_extensions_atoms.proto + */ + enum class EnterReason(val reason: Int) { + UNKNOWN_ENTER( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__UNKNOWN_ENTER + ), + OVERVIEW( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__OVERVIEW + ), + APP_HANDLE_DRAG( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_HANDLE_DRAG + ), + APP_HANDLE_MENU_BUTTON( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_HANDLE_MENU_BUTTON + ), + APP_FREEFORM_INTENT( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_FREEFORM_INTENT + ), + KEYBOARD_SHORTCUT_ENTER( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__KEYBOARD_SHORTCUT_ENTER + ), + SCREEN_ON( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__SCREEN_ON + ); + } + + /** + * Enum ExitReason mapped to the ExitReason definition in + * stats/atoms/desktopmode/desktopmode_extensions_atoms.proto + */ + enum class ExitReason(val reason: Int) { + UNKNOWN_EXIT( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__UNKNOWN_EXIT + ), + DRAG_TO_EXIT( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__DRAG_TO_EXIT + ), + APP_HANDLE_MENU_BUTTON_EXIT( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__APP_HANDLE_MENU_BUTTON_EXIT + ), + KEYBOARD_SHORTCUT_EXIT( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__KEYBOARD_SHORTCUT_EXIT + ), + RETURN_HOME_OR_OVERVIEW( + FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME + ), + TASK_FINISHED( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__TASK_FINISHED + ), + SCREEN_OFF( + FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__SCREEN_OFF + ) + } + + private const val DESKTOP_MODE_ATOM_ID = FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED + private const val DESKTOP_MODE_TASK_UPDATE_ATOM_ID = + FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java index 88949b2a5acd..22ba70860587 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java @@ -18,21 +18,13 @@ package com.android.wm.shell.desktopmode; import android.os.SystemProperties; -import com.android.wm.shell.Flags; +import com.android.window.flags.Flags; /** * Constants for desktop mode feature */ public class DesktopModeStatus { - private static final boolean ENABLE_DESKTOP_WINDOWING = Flags.enableDesktopWindowing(); - - /** - * Flag to indicate whether desktop mode proto is available on the device - */ - private static final boolean IS_PROTO2_ENABLED = SystemProperties.getBoolean( - "persist.wm.debug.desktop_mode_2", false); - /** * Flag to indicate whether task resizing is veiled. */ @@ -75,16 +67,10 @@ public class DesktopModeStatus { "persist.wm.debug.desktop_use_rounded_corners", true); /** - * Return {@code true} is desktop windowing proto 2 is enabled + * Return {@code true} if desktop windowing is enabled */ public static boolean isEnabled() { - // Check for aconfig flag first - if (ENABLE_DESKTOP_WINDOWING) { - return true; - } - // Fall back to sysprop flag - // TODO(b/304778354): remove sysprop once desktop aconfig flag supports dynamic overriding - return IS_PROTO2_ENABLED; + return Flags.enableDesktopWindowingMode(); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java index 405341803a46..7091c4b7210a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java @@ -22,8 +22,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; -import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE; - import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.RectEvaluator; @@ -389,7 +387,8 @@ public class DesktopModeVisualIndicator { layout.width() - padding, layout.height() - padding); case TO_DESKTOP_INDICATOR: - final float adjustmentPercentage = 1f - FINAL_FREEFORM_SCALE; + final float adjustmentPercentage = 1f + - DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE; return new Rect((int) (adjustmentPercentage * layout.width() / 2), (int) (adjustmentPercentage * layout.height() / 2), (int) (layout.width() - (adjustmentPercentage * layout.width() / 2)), diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 98f9988eaabb..b9d0342137c5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -16,7 +16,6 @@ package com.android.wm.shell.desktopmode -import android.app.ActivityManager import android.app.ActivityManager.RunningTaskInfo import android.app.ActivityOptions import android.app.PendingIntent @@ -35,7 +34,6 @@ import android.graphics.Rect import android.graphics.Region import android.os.IBinder import android.os.SystemProperties -import android.util.DisplayMetrics.DENSITY_DEFAULT import android.view.Display.DEFAULT_DISPLAY import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE @@ -51,6 +49,7 @@ import com.android.internal.policy.ScreenDecorationsUtils import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.DisplayController +import com.android.wm.shell.common.DisplayLayout import com.android.wm.shell.common.ExecutorUtils import com.android.wm.shell.common.ExternalInterfaceBinder import com.android.wm.shell.common.LaunchAdjacentController @@ -68,7 +67,6 @@ import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksLi import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener import com.android.wm.shell.draganddrop.DragAndDropController import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE -import com.android.wm.shell.recents.RecentTasksController import com.android.wm.shell.recents.RecentsTransitionHandler import com.android.wm.shell.recents.RecentsTransitionStateListener import com.android.wm.shell.splitscreen.SplitScreenController @@ -85,7 +83,6 @@ import com.android.wm.shell.windowdecor.OnTaskResizeAnimationListener import java.io.PrintWriter import java.util.concurrent.Executor import java.util.function.Consumer -import java.util.function.Function /** Handles moving tasks in and out of desktop */ class DesktopTasksController( @@ -384,6 +381,18 @@ class DesktopTasksController( } } + /** Enter fullscreen by moving the focused freeform task in given `displayId` to fullscreen. */ + fun enterFullscreen(displayId: Int) { + if (DesktopModeStatus.isEnabled()) { + shellTaskOrganizer + .getRunningTasks(displayId) + .find { taskInfo -> + taskInfo.isFocused && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM + } + ?.let { moveToFullscreenWithAnimation(it, it.positionInParent) } + } + } + /** Move a desktop app to split screen. */ fun moveToSplit(task: RunningTaskInfo) { KtProtoLog.v( @@ -551,11 +560,7 @@ class DesktopTasksController( if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) { // The desktop task is currently occupying the whole stable bounds, toggle to the // default bounds. - getDefaultDesktopTaskBounds( - density = taskInfo.configuration.densityDpi.toFloat() / DENSITY_DEFAULT, - stableBounds = stableBounds, - outBounds = destinationBounds - ) + getDefaultDesktopTaskBounds(displayLayout, destinationBounds) } else { // Toggle to the stable bounds. destinationBounds.set(stableBounds) @@ -610,15 +615,17 @@ class DesktopTasksController( } } - private fun getDefaultDesktopTaskBounds(density: Float, stableBounds: Rect, outBounds: Rect) { - val width = (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f).toInt() - val height = (DESKTOP_MODE_DEFAULT_HEIGHT_DP * density + 0.5f).toInt() - outBounds.set(0, 0, width, height) - // Center the task in stable bounds + private fun getDefaultDesktopTaskBounds(displayLayout: DisplayLayout, outBounds: Rect) { + // TODO(b/319819547): Account for app constraints so apps do not become letterboxed + val screenBounds = Rect(0, 0, displayLayout.width(), displayLayout.height()) + // Update width and height with default desktop mode values + val desiredWidth = screenBounds.width().times(DESKTOP_MODE_INITIAL_BOUNDS_SCALE).toInt() + val desiredHeight = screenBounds.height().times(DESKTOP_MODE_INITIAL_BOUNDS_SCALE).toInt() + outBounds.set(0, 0, desiredWidth, desiredHeight) + // Center the task in screen bounds outBounds.offset( - stableBounds.centerX() - outBounds.centerX(), - stableBounds.centerY() - outBounds.centerY() - ) + screenBounds.centerX() - outBounds.centerX(), + screenBounds.centerY() - outBounds.centerY()) } /** @@ -1113,6 +1120,12 @@ class DesktopTasksController( this@DesktopTasksController.enterDesktop(displayId) } } + + override fun moveFocusedTaskToFullscreen(displayId: Int) { + mainExecutor.execute { + this@DesktopTasksController.enterFullscreen(displayId) + } + } } /** The interface for calls from outside the host process. */ @@ -1233,13 +1246,9 @@ class DesktopTasksController( SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 284) private val DESKTOP_DENSITY_ALLOWED_RANGE = (100..1000) - // Override default freeform task width when desktop mode is enabled. In dips. - private val DESKTOP_MODE_DEFAULT_WIDTH_DP = - SystemProperties.getInt("persist.wm.debug.desktop_mode.default_width", 840) - - // Override default freeform task height when desktop mode is enabled. In dips. - private val DESKTOP_MODE_DEFAULT_HEIGHT_DP = - SystemProperties.getInt("persist.wm.debug.desktop_mode.default_height", 630) + @JvmField + val DESKTOP_MODE_INITIAL_BOUNDS_SCALE = SystemProperties + .getInt("persist.wm.debug.freeform_initial_bounds_scale", 75) / 100f /** * Check if desktop density override is enabled diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java index 07cf202ddfac..79bb5408df82 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java @@ -54,8 +54,6 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition private final Transitions mTransitions; private final Supplier<SurfaceControl.Transaction> mTransactionSupplier; - // The size of the screen after drag relative to the fullscreen size - public static final float FINAL_FREEFORM_SCALE = 0.6f; public static final int FREEFORM_ANIMATION_DURATION = 336; private final List<IBinder> mPendingTransitionTokens = new ArrayList<>(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java index 1afbdf90eac0..7da1b23dd5b1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java @@ -59,7 +59,6 @@ import androidx.annotation.BinderThread; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; -import com.android.internal.logging.InstanceId; import com.android.internal.logging.UiEventLogger; import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; @@ -316,12 +315,11 @@ public class DragAndDropController implements RemoteCallable<DragAndDropControll return false; } // TODO(b/290391688): Also update the session data with task stack changes - InstanceId loggerSessionId = mLogger.logStart(event); - pd.activeDragCount++; - pd.dragSession = new DragSession(mContext, ActivityTaskManager.getInstance(), + pd.dragSession = new DragSession(ActivityTaskManager.getInstance(), mDisplayController.getDisplayLayout(displayId), event.getClipData()); pd.dragSession.update(); - pd.dragLayout.prepare(pd.dragSession, loggerSessionId); + pd.activeDragCount++; + pd.dragLayout.prepare(pd.dragSession, mLogger.logStart(pd.dragSession)); setDropTargetWindowVisibility(pd, View.VISIBLE); notifyListeners(l -> { l.onDragStarted(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java index 2a7dd5aeb341..75b126c47690 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropEventLogger.java @@ -53,17 +53,21 @@ public class DragAndDropEventLogger { /** * Logs the start of a drag. */ - public InstanceId logStart(DragEvent event) { - final ClipDescription description = event.getClipDescription(); - final ClipData data = event.getClipData(); - final ClipData.Item item = data.getItemAt(0); - mInstanceId = item.getIntent().getParcelableExtra( - ClipDescription.EXTRA_LOGGING_INSTANCE_ID); + public InstanceId logStart(DragSession session) { + mInstanceId = session.appData != null + ? session.appData.getParcelableExtra(ClipDescription.EXTRA_LOGGING_INSTANCE_ID, + InstanceId.class) + : null; if (mInstanceId == null) { mInstanceId = mIdSequence.newInstanceId(); } - mActivityInfo = item.getActivityInfo(); - log(getStartEnum(description), mActivityInfo); + mActivityInfo = session.activityInfo; + if (session.appData != null) { + log(getStartEnum(session.getClipDescription()), mActivityInfo); + } else { + // TODO(b/255649902): Update this once we have a new enum + log(DragAndDropUiEventEnum.GLOBAL_APP_DRAG_START_ACTIVITY, mActivityInfo); + } return mInstanceId; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java index a31a773a76a0..eb82da8a8e9f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropPolicy.java @@ -29,6 +29,8 @@ import static android.content.Intent.EXTRA_PACKAGE_NAME; import static android.content.Intent.EXTRA_SHORTCUT_ID; import static android.content.Intent.EXTRA_TASK_ID; import static android.content.Intent.EXTRA_USER; +import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; @@ -52,9 +54,11 @@ import android.content.pm.LauncherApps; import android.graphics.Insets; import android.graphics.Rect; import android.graphics.RectF; +import android.os.Build; import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; +import android.util.Log; import android.util.Slog; import androidx.annotation.IntDef; @@ -63,8 +67,10 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.internal.logging.InstanceId; +import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.R; import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition; +import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; import java.lang.annotation.Retention; @@ -104,7 +110,9 @@ public class DragAndDropPolicy { void start(DragSession session, InstanceId loggerSessionId) { mLoggerSessionId = loggerSessionId; mSession = session; - RectF disallowHitRegion = (RectF) mSession.dragData.getExtra(EXTRA_DISALLOW_HIT_REGION); + RectF disallowHitRegion = mSession.appData != null + ? (RectF) mSession.appData.getExtra(EXTRA_DISALLOW_HIT_REGION) + : null; if (disallowHitRegion == null) { mDisallowHitRegion.setEmpty(); } else { @@ -223,7 +231,7 @@ public class DragAndDropPolicy { } @VisibleForTesting - void handleDrop(Target target, ClipData data) { + void handleDrop(Target target) { if (target == null || !mTargets.contains(target)) { return; } @@ -238,41 +246,77 @@ public class DragAndDropPolicy { mSplitScreen.onDroppedToSplit(position, mLoggerSessionId); } - final ClipDescription description = data.getDescription(); - final Intent dragData = mSession.dragData; - startClipDescription(description, dragData, position); + if (mSession.appData != null) { + launchApp(mSession, position); + } else { + launchIntent(mSession, position); + } } - private void startClipDescription(ClipDescription description, Intent intent, - @SplitPosition int position) { + /** + * Launches an app provided by SysUI. + */ + private void launchApp(DragSession session, @SplitPosition int position) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Launching app data at position=%d", + position); + final ClipDescription description = session.getClipDescription(); final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK); final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT); final ActivityOptions baseActivityOpts = ActivityOptions.makeBasic(); baseActivityOpts.setDisallowEnterPictureInPictureWhileLaunching(true); final Bundle opts = baseActivityOpts.toBundle(); - if (intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)) { - opts.putAll(intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)); + if (session.appData.hasExtra(EXTRA_ACTIVITY_OPTIONS)) { + opts.putAll(session.appData.getBundleExtra(EXTRA_ACTIVITY_OPTIONS)); } // Put BAL flags to avoid activity start aborted. opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true); opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, true); - final UserHandle user = intent.getParcelableExtra(EXTRA_USER); + final UserHandle user = session.appData.getParcelableExtra(EXTRA_USER); if (isTask) { - final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID); + final int taskId = session.appData.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID); mStarter.startTask(taskId, position, opts); } else if (isShortcut) { - final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME); - final String id = intent.getStringExtra(EXTRA_SHORTCUT_ID); + final String packageName = session.appData.getStringExtra(EXTRA_PACKAGE_NAME); + final String id = session.appData.getStringExtra(EXTRA_SHORTCUT_ID); mStarter.startShortcut(packageName, id, position, opts, user); } else { - final PendingIntent launchIntent = intent.getParcelableExtra(EXTRA_PENDING_INTENT); + final PendingIntent launchIntent = + session.appData.getParcelableExtra(EXTRA_PENDING_INTENT); + if (Build.IS_DEBUGGABLE) { + if (!user.equals(launchIntent.getCreatorUserHandle())) { + Log.e(TAG, "Expected app intent's EXTRA_USER to match pending intent user"); + } + } mStarter.startIntent(launchIntent, user.getIdentifier(), null /* fillIntent */, position, opts); } } /** + * Launches an intent sender provided by an application. + */ + private void launchIntent(DragSession session, @SplitPosition int position) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Launching intent at position=%d", + position); + final ActivityOptions baseActivityOpts = ActivityOptions.makeBasic(); + baseActivityOpts.setDisallowEnterPictureInPictureWhileLaunching(true); + // TODO(b/255649902): Rework this so that SplitScreenController can always use the options + // instead of a fillInIntent since it's assuming that the PendingIntent is mutable + baseActivityOpts.setPendingIntentLaunchFlags(FLAG_ACTIVITY_NEW_TASK + | FLAG_ACTIVITY_MULTIPLE_TASK); + + final Bundle opts = baseActivityOpts.toBundle(); + // Put BAL flags to avoid activity start aborted. + opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED, true); + opts.putBoolean(KEY_PENDING_INTENT_BACKGROUND_ACTIVITY_ALLOWED_BY_PERMISSION, true); + + mStarter.startIntent(session.launchableIntent, + session.launchableIntent.getCreatorUserHandle().getIdentifier(), + null /* fillIntent */, position, opts); + } + + /** * Interface for actually committing the task launches. */ public interface Starter { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java index 619f624ff3bc..ecb53dc17a48 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java @@ -22,6 +22,8 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.content.pm.ActivityInfo.CONFIG_ASSETS_PATHS; import static android.content.pm.ActivityInfo.CONFIG_UI_MODE; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; +import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; @@ -38,12 +40,15 @@ import android.app.ActivityManager; import android.app.StatusBarManager; import android.content.Context; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Color; import android.graphics.Insets; import android.graphics.Rect; +import android.graphics.Region; import android.graphics.drawable.Drawable; import android.view.DragEvent; import android.view.SurfaceControl; +import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.WindowInsets.Type; import android.widget.LinearLayout; @@ -65,7 +70,8 @@ import java.util.ArrayList; /** * Coordinates the visible drop targets for the current drag within a single display. */ -public class DragLayout extends LinearLayout { +public class DragLayout extends LinearLayout + implements ViewTreeObserver.OnComputeInternalInsetsListener { // While dragging the status bar is hidden. private static final int HIDE_STATUS_BAR_FLAGS = StatusBarManager.DISABLE_NOTIFICATION_ICONS @@ -90,7 +96,9 @@ public class DragLayout extends LinearLayout { private int mDisplayMargin; private int mDividerSize; + private int mLaunchIntentEdgeMargin; private Insets mInsets = Insets.NONE; + private Region mTouchableRegion; private boolean mIsShowing; private boolean mHasDropped; @@ -106,10 +114,11 @@ public class DragLayout extends LinearLayout { mStatusBarManager = context.getSystemService(StatusBarManager.class); mLastConfiguration.setTo(context.getResources().getConfiguration()); - mDisplayMargin = context.getResources().getDimensionPixelSize( - R.dimen.drop_layout_display_margin); - mDividerSize = context.getResources().getDimensionPixelSize( - R.dimen.split_divider_bar_width); + final Resources res = context.getResources(); + mDisplayMargin = res.getDimensionPixelSize(R.dimen.drop_layout_display_margin); + mDividerSize = res.getDimensionPixelSize(R.dimen.split_divider_bar_width); + mLaunchIntentEdgeMargin = + res.getDimensionPixelSize(R.dimen.drag_launchable_intent_edge_margin); // Always use LTR because we assume dropZoneView1 is on the left and 2 is on the right when // showing the highlight. @@ -131,6 +140,66 @@ public class DragLayout extends LinearLayout { } @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mTouchableRegion = Region.obtain(); + getViewTreeObserver().addOnComputeInternalInsetsListener(this); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + getViewTreeObserver().removeOnComputeInternalInsetsListener(this); + mTouchableRegion.recycle(); + } + + @Override + public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inOutInfo) { + if (mSession != null && mSession.launchableIntent != null) { + inOutInfo.touchableRegion.set(mTouchableRegion); + inOutInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION); + } + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + updateTouchableRegion(); + } + + /** + * Updates the touchable region, this should be called after any configuration changes have + * been applied. + */ + private void updateTouchableRegion() { + mTouchableRegion.setEmpty(); + if (mSession != null && mSession.launchableIntent != null) { + final int width = getMeasuredWidth(); + final int height = getMeasuredHeight(); + if (mIsLeftRightSplit) { + mTouchableRegion.union( + new Rect(0, 0, mInsets.left + mLaunchIntentEdgeMargin, height)); + mTouchableRegion.union( + new Rect(width - mInsets.right - mLaunchIntentEdgeMargin, 0, width, + height)); + } else { + mTouchableRegion.union( + new Rect(0, 0, width, mInsets.top + mLaunchIntentEdgeMargin)); + mTouchableRegion.union( + new Rect(0, height - mInsets.bottom - mLaunchIntentEdgeMargin, width, + height)); + } + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, + "Updating drag layout width=%d height=%d touchable region=%s", + width, height, mTouchableRegion); + + // Reapply insets to update the touchable region + requestApplyInsets(); + } + } + + + @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { mInsets = insets.getInsets(Type.tappableElement() | Type.displayCutout()); recomputeDropTargets(); @@ -164,6 +233,7 @@ public class DragLayout extends LinearLayout { mDropZoneView2.onThemeChange(); } mLastConfiguration.setTo(newConfig); + requestLayout(); } private void updateContainerMarginsForSingleTask() { @@ -242,6 +312,7 @@ public class DragLayout extends LinearLayout { mSplitScreenController.getStageBounds(topOrLeftBounds, bottomOrRightBounds); updateDropZoneSizes(topOrLeftBounds, bottomOrRightBounds); } + requestLayout(); } private void updateDropZoneSizesForSingleTask() { @@ -392,7 +463,7 @@ public class DragLayout extends LinearLayout { mHasDropped = true; // Process the drop - mPolicy.handleDrop(mCurrentTarget, event.getClipData()); + mPolicy.handleDrop(mCurrentTarget); // Start animating the drop UI out with the drag surface hide(event, dropCompleteCallback); @@ -505,5 +576,7 @@ public class DragLayout extends LinearLayout { pw.println(innerPrefix + "mIsShowing=" + mIsShowing); pw.println(innerPrefix + "mHasDropped=" + mHasDropped); pw.println(innerPrefix + "mCurrentTarget=" + mCurrentTarget); + pw.println(innerPrefix + "mInsets=" + mInsets); + pw.println(innerPrefix + "mTouchableRegion=" + mTouchableRegion); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java index 353d702e5bc4..8f1bc59af1ef 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragSession.java @@ -21,12 +21,15 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import android.app.ActivityManager; import android.app.ActivityTaskManager; +import android.app.PendingIntent; import android.app.WindowConfiguration; import android.content.ClipData; -import android.content.Context; +import android.content.ClipDescription; import android.content.Intent; import android.content.pm.ActivityInfo; +import androidx.annotation.Nullable; + import com.android.wm.shell.common.DisplayLayout; import java.util.List; @@ -39,7 +42,18 @@ public class DragSession { private final ClipData mInitialDragData; final DisplayLayout displayLayout; - Intent dragData; + // The activity info associated with the activity in the appData or the launchableIntent + @Nullable + ActivityInfo activityInfo; + // The intent bundle that includes data about an app-type drag that is started by + // Launcher/SysUI. Only one of appDragData OR launchableIntent will be non-null for a session. + @Nullable + Intent appData; + // A launchable intent that is specified in the ClipData directly. + // Only one of appDragData OR launchableIntent will be non-null for a session. + @Nullable + PendingIntent launchableIntent; + // Stores the current running task at the time that the drag was initiated ActivityManager.RunningTaskInfo runningTaskInfo; @WindowConfiguration.WindowingMode int runningTaskWinMode = WINDOWING_MODE_UNDEFINED; @@ -47,7 +61,7 @@ public class DragSession { int runningTaskActType = ACTIVITY_TYPE_STANDARD; boolean dragItemSupportsSplitscreen; - DragSession(Context context, ActivityTaskManager activityTaskManager, + DragSession(ActivityTaskManager activityTaskManager, DisplayLayout dispLayout, ClipData data) { mActivityTaskManager = activityTaskManager; mInitialDragData = data; @@ -55,6 +69,14 @@ public class DragSession { } /** + * Returns the clip description associated with the drag. + * @return + */ + ClipDescription getClipDescription() { + return mInitialDragData.getDescription(); + } + + /** * Updates the session data based on the current state of the system. */ void update() { @@ -67,9 +89,11 @@ public class DragSession { runningTaskActType = task.getActivityType(); } - final ActivityInfo info = mInitialDragData.getItemAt(0).getActivityInfo(); - dragItemSupportsSplitscreen = info == null - || ActivityInfo.isResizeableMode(info.resizeMode); - dragData = mInitialDragData.getItemAt(0).getIntent(); + activityInfo = mInitialDragData.getItemAt(0).getActivityInfo(); + // TODO: This should technically check & respect config_supportsNonResizableMultiWindow + dragItemSupportsSplitscreen = activityInfo == null + || ActivityInfo.isResizeableMode(activityInfo.resizeMode); + appData = mInitialDragData.getItemAt(0).getIntent(); + launchableIntent = DragUtils.getLaunchIntent(mInitialDragData); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java index f7bcc9477aa1..24f8e186bf76 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragUtils.java @@ -36,8 +36,21 @@ public class DragUtils { * Returns whether we can handle this particular drag. */ public static boolean canHandleDrag(DragEvent event) { - return event.getClipData().getItemCount() > 0 - && (isAppDrag(event.getClipDescription())); + if (event.getClipData().getItemCount() <= 0) { + // No clip data, ignore this drag + return false; + } + if (isAppDrag(event.getClipDescription())) { + // Clip data contains an app drag initiated from SysUI, handle it + return true; + } + if (com.android.window.flags.Flags.delegateUnhandledDrags() + && getLaunchIntent(event) != null) { + // Clip data contains a launchable intent drag, handle it + return true; + } + // Otherwise ignore + return false; } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java index e018ecc0f7e3..6a1a62ea30a1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java @@ -1037,6 +1037,7 @@ public class PipTransition extends PipTransitionController { private void computeEnterPipRotatedBounds(int rotationDelta, int startRotation, int endRotation, TaskInfo taskInfo, Rect outDestinationBounds, @Nullable Rect outSourceHintRect) { mPipDisplayLayoutState.rotateTo(endRotation); + mPipBoundsState.updateMinMaxSize(mPipBoundsState.getAspectRatio()); final Rect displayBounds = mPipDisplayLayoutState.getDisplayBounds(); outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 46840773cfc6..2cdec81d77ac 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -976,8 +976,16 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipBoundsState.addNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG, hotseatKeepClearArea); onDisplayRotationChangedNotInPip(mContext, launcherRotation); + // cache current min/max size + Point minSize = mPipBoundsState.getMinSize(); + Point maxSize = mPipBoundsState.getMaxSize(); + mPipBoundsState.updateMinMaxSize(pictureInPictureParams.getAspectRatioFloat()); final Rect entryBounds = mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo, pictureInPictureParams); + // restore min/max size, as this is referenced later in OnDisplayChangingListener and needs + // to reflect the pre-rotation state for it to work + mPipBoundsState.setMinSize(minSize.x, minSize.y); + mPipBoundsState.setMaxSize(maxSize.x, maxSize.y); // sync mPipBoundsState with the newly calculated bounds. mPipBoundsState.setNormalBounds(entryBounds); return entryBounds; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java index e7dd31cc1fa9..c1adfffce074 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java @@ -467,17 +467,11 @@ public class PipTouchHandler { } private void updatePinchResizeSizeConstraints(float aspectRatio) { - final int minWidth, minHeight, maxWidth, maxHeight; - - minWidth = mSizeSpecSource.getMinSize(aspectRatio).getWidth(); - minHeight = mSizeSpecSource.getMinSize(aspectRatio).getHeight(); - maxWidth = mSizeSpecSource.getMaxSize(aspectRatio).getWidth(); - maxHeight = mSizeSpecSource.getMaxSize(aspectRatio).getHeight(); - - mPipResizeGestureHandler.updateMinSize(minWidth, minHeight); - mPipResizeGestureHandler.updateMaxSize(maxWidth, maxHeight); - mPipBoundsState.setMaxSize(maxWidth, maxHeight); - mPipBoundsState.setMinSize(minWidth, minHeight); + mPipBoundsState.updateMinMaxSize(aspectRatio); + mPipResizeGestureHandler.updateMinSize(mPipBoundsState.getMinSize().x, + mPipBoundsState.getMinSize().y); + mPipResizeGestureHandler.updateMaxSize(mPipBoundsState.getMaxSize().x, + mPipBoundsState.getMaxSize().y); } /** diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java deleted file mode 100644 index 93ffb3dc8115..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2020 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.wm.shell.protolog; - -import android.annotation.Nullable; - -import com.android.internal.protolog.BaseProtoLogImpl; -import com.android.internal.protolog.ProtoLogViewerConfigReader; -import com.android.internal.protolog.common.IProtoLogGroup; - -import java.io.File; -import java.io.PrintWriter; - - -/** - * A service for the ProtoLog logging system. - */ -public class ShellProtoLogImpl extends BaseProtoLogImpl { - private static final String TAG = "ProtoLogImpl"; - private static final int BUFFER_CAPACITY = 1024 * 1024; - // TODO: find a proper location to save the protolog message file - private static final String LOG_FILENAME = "/data/misc/wmtrace/shell_log.winscope"; - private static final String VIEWER_CONFIG_FILENAME = "/system_ext/etc/wmshell.protolog.json.gz"; - - private static ShellProtoLogImpl sServiceInstance = null; - - static { - addLogGroupEnum(ShellProtoLogGroup.values()); - } - - /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ - public static void d(IProtoLogGroup group, int messageHash, int paramsMask, - @Nullable String messageString, - Object... args) { - getSingleInstance() - .log(LogLevel.DEBUG, group, messageHash, paramsMask, messageString, args); - } - - /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ - public static void v(IProtoLogGroup group, int messageHash, int paramsMask, - @Nullable String messageString, - Object... args) { - getSingleInstance().log(LogLevel.VERBOSE, group, messageHash, paramsMask, messageString, - args); - } - - /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ - public static void i(IProtoLogGroup group, int messageHash, int paramsMask, - @Nullable String messageString, - Object... args) { - getSingleInstance().log(LogLevel.INFO, group, messageHash, paramsMask, messageString, args); - } - - /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ - public static void w(IProtoLogGroup group, int messageHash, int paramsMask, - @Nullable String messageString, - Object... args) { - getSingleInstance().log(LogLevel.WARN, group, messageHash, paramsMask, messageString, args); - } - - /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ - public static void e(IProtoLogGroup group, int messageHash, int paramsMask, - @Nullable String messageString, - Object... args) { - getSingleInstance() - .log(LogLevel.ERROR, group, messageHash, paramsMask, messageString, args); - } - - /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */ - public static void wtf(IProtoLogGroup group, int messageHash, int paramsMask, - @Nullable String messageString, - Object... args) { - getSingleInstance().log(LogLevel.WTF, group, messageHash, paramsMask, messageString, args); - } - - /** Returns true iff logging is enabled for the given {@code IProtoLogGroup}. */ - public static boolean isEnabled(IProtoLogGroup group) { - return group.isLogToLogcat() - || (group.isLogToProto() && getSingleInstance().isProtoEnabled()); - } - - /** - * Returns the single instance of the ProtoLogImpl singleton class. - */ - public static synchronized ShellProtoLogImpl getSingleInstance() { - if (sServiceInstance == null) { - sServiceInstance = new ShellProtoLogImpl(); - } - return sServiceInstance; - } - - public int startTextLogging(String[] groups, PrintWriter pw) { - mViewerConfig.loadViewerConfig(pw, VIEWER_CONFIG_FILENAME); - return setLogging(true /* setTextLogging */, true, pw, groups); - } - - public int stopTextLogging(String[] groups, PrintWriter pw) { - return setLogging(true /* setTextLogging */, false, pw, groups); - } - - private ShellProtoLogImpl() { - super(new File(LOG_FILENAME), VIEWER_CONFIG_FILENAME, BUFFER_CAPACITY, - new ProtoLogViewerConfigReader()); - } -} - diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java index 53dd981755d2..952e2d4b3b9a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java @@ -476,7 +476,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, } public void goToFullscreenFromSplit() { - mStageCoordinator.goToFullscreenFromSplit(); + if (mStageCoordinator.isSplitActive()) { + mStageCoordinator.goToFullscreenFromSplit(); + } } /** Move the specified task to fullscreen, regardless of focus state. */ @@ -806,6 +808,9 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, @Override public void startIntent(PendingIntent intent, int userId1, @Nullable Intent fillInIntent, @SplitPosition int position, @Nullable Bundle options) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, + "startIntent(): intent=%s user=%d fillInIntent=%s position=%d", intent, userId1, + fillInIntent, position); // Flag this as a no-user-action launch to prevent sending user leaving event to the current // top activity since it's going to be put into another side of the split. This prevents the // current top activity from going into pip mode due to user leaving event. @@ -824,6 +829,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, .map(recentTasks -> recentTasks.findTaskInBackground(component, userId1)) .orElse(null); if (taskInfo != null) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, + "Found suitable background task=%s", taskInfo); if (ENABLE_SHELL_TRANSITIONS) { mStageCoordinator.startTask(taskInfo.taskId, position, options); } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index fa14b4c64fe0..2933cf48614a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -3396,6 +3396,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final int stageType = isMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE; final WindowContainerTransaction wct = new WindowContainerTransaction(); prepareExitSplitScreen(stageType, wct); + clearSplitPairedInRecents(EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW); mSplitTransitions.startDismissTransition(wct, StageCoordinator.this, stageType, EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW); Log.w(TAG, splitFailureMessage("onNoLongerSupportMultiWindow", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java index c70a8219489e..9130edfa9f26 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java @@ -470,10 +470,12 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler { } final float cornerRadius; - if (a.hasRoundedCorners() && isTask) { - // hasRoundedCorners is currently only enabled for tasks + if (a.hasRoundedCorners()) { + final int displayId = isTask ? change.getTaskInfo().displayId + : info.getRoot(TransitionUtil.rootIndexFor(change, info)) + .getDisplayId(); final Context displayContext = - mDisplayController.getDisplayContext(change.getTaskInfo().displayId); + mDisplayController.getDisplayContext(displayId); cornerRadius = displayContext == null ? 0 : ScreenDecorationsUtils.getWindowCornerRadius(displayContext); } else { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt index 9b48a542720c..7a50814f0275 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.util import android.util.Log import com.android.internal.protolog.common.IProtoLogGroup -import com.android.wm.shell.protolog.ShellProtoLogImpl +import com.android.internal.protolog.common.ProtoLog /** * Log messages using an API similar to [com.android.internal.protolog.common.ProtoLog]. Useful for @@ -31,42 +31,42 @@ class KtProtoLog { companion object { /** @see [com.android.internal.protolog.common.ProtoLog.d] */ fun d(group: IProtoLogGroup, messageString: String, vararg args: Any) { - if (ShellProtoLogImpl.isEnabled(group)) { + if (ProtoLog.isEnabled(group)) { Log.d(group.tag, String.format(messageString, *args)) } } /** @see [com.android.internal.protolog.common.ProtoLog.v] */ fun v(group: IProtoLogGroup, messageString: String, vararg args: Any) { - if (ShellProtoLogImpl.isEnabled(group)) { + if (ProtoLog.isEnabled(group)) { Log.v(group.tag, String.format(messageString, *args)) } } /** @see [com.android.internal.protolog.common.ProtoLog.i] */ fun i(group: IProtoLogGroup, messageString: String, vararg args: Any) { - if (ShellProtoLogImpl.isEnabled(group)) { + if (ProtoLog.isEnabled(group)) { Log.i(group.tag, String.format(messageString, *args)) } } /** @see [com.android.internal.protolog.common.ProtoLog.w] */ fun w(group: IProtoLogGroup, messageString: String, vararg args: Any) { - if (ShellProtoLogImpl.isEnabled(group)) { + if (ProtoLog.isEnabled(group)) { Log.w(group.tag, String.format(messageString, *args)) } } /** @see [com.android.internal.protolog.common.ProtoLog.e] */ fun e(group: IProtoLogGroup, messageString: String, vararg args: Any) { - if (ShellProtoLogImpl.isEnabled(group)) { + if (ProtoLog.isEnabled(group)) { Log.e(group.tag, String.format(messageString, *args)) } } /** @see [com.android.internal.protolog.common.ProtoLog.wtf] */ fun wtf(group: IProtoLogGroup, messageString: String, vararg args: Any) { - if (ShellProtoLogImpl.isEnabled(group)) { + if (ProtoLog.isEnabled(group)) { Log.wtf(group.tag, String.format(messageString, *args)) } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index 5b8ffb30dc4a..caa894fcbbc7 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -22,13 +22,14 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.view.InputDevice.SOURCE_TOUCHSCREEN; +import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_HOVER_ENTER; import static android.view.MotionEvent.ACTION_HOVER_EXIT; +import static android.view.MotionEvent.ACTION_UP; import static android.view.WindowInsets.Type.statusBars; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; -import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE; import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION; import static com.android.wm.shell.windowdecor.MoveToDesktopAnimator.DRAG_FREEFORM_SCALE; @@ -60,7 +61,6 @@ import android.view.MotionEvent; import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.View; -import android.view.ViewConfiguration; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; @@ -322,8 +322,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private final GestureDetector mGestureDetector; private boolean mIsDragging; + private boolean mTouchscreenInUse; private boolean mHasLongClicked; - private boolean mShouldClick; private int mDragPointerId = -1; private final Runnable mCloseMaximizeWindowRunnable; @@ -344,6 +344,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { @Override public void onClick(View v) { + if (mIsDragging) { + mIsDragging = false; + return; + } final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); final int id = v.getId(); if (id == R.id.close_window) { @@ -422,6 +426,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { @Override public boolean onTouch(View v, MotionEvent e) { final int id = v.getId(); + if ((e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN) { + mTouchscreenInUse = e.getActionMasked() != ACTION_UP + && e.getActionMasked() != ACTION_CANCEL; + } if (id != R.id.caption_handle && id != R.id.desktop_mode_caption && id != R.id.open_menu_button && id != R.id.close_window && id != R.id.maximize_window) { @@ -433,31 +441,19 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { if (!mHasLongClicked && id != R.id.maximize_window) { decoration.closeMaximizeMenuIfNeeded(e); } - - final long eventDuration = e.getEventTime() - e.getDownTime(); - final boolean isTouchScreen = - (e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN; - final boolean shouldLongClick = isTouchScreen && id == R.id.maximize_window - && !mIsDragging && !mHasLongClicked - && eventDuration >= ViewConfiguration.getLongPressTimeout(); - if (shouldLongClick) { - v.performLongClick(); - mHasLongClicked = true; - return true; - } - return mDragDetector.onMotionEvent(v, e); } @Override public boolean onLongClick(View v) { final int id = v.getId(); - if (id == R.id.maximize_window) { + if (id == R.id.maximize_window && mTouchscreenInUse) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId); moveTaskToFront(decoration.mTaskInfo); if (decoration.isMaximizeMenuActive()) { decoration.closeMaximizeMenu(); } else { + mHasLongClicked = true; decoration.createMaximizeMenu(); } return true; @@ -516,11 +512,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { if (mGestureDetector.onTouchEvent(e)) { return true; } - if (e.getActionMasked() == MotionEvent.ACTION_CANCEL) { - // If a motion event is cancelled, reset mShouldClick so a click is not accidentally - // performed. - mShouldClick = false; - } + final int id = v.getId(); + final boolean touchingButton = (id == R.id.close_window || id == R.id.maximize_window + || id == R.id.open_menu_button); switch (e.getActionMasked()) { case MotionEvent.ACTION_DOWN: { mDragPointerId = e.getPointerId(0); @@ -528,12 +522,12 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { 0 /* ctrlType */, e.getRawX(0), e.getRawY(0)); mIsDragging = false; - mShouldClick = true; mHasLongClicked = false; - return true; + // Do not consume input event if a button is touched, otherwise it would + // prevent the button's ripple effect from showing. + return !touchingButton; } case MotionEvent.ACTION_MOVE: { - mShouldClick = false; // If a decor's resize drag zone is active, don't also try to reposition it. if (decoration.isHandlingDragResize()) break; decoration.closeMaximizeMenu(); @@ -554,11 +548,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { case MotionEvent.ACTION_CANCEL: { final boolean wasDragging = mIsDragging; if (!wasDragging) { - if (mShouldClick && v != null && !mHasLongClicked) { - v.performClick(); - mShouldClick = false; - return true; - } return false; } if (e.findPointerIndex(mDragPointerId) == -1) { @@ -577,8 +566,15 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { position, new PointF(e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx)), newTaskBounds)); - mIsDragging = false; - return true; + if (touchingButton && !mHasLongClicked) { + // We need the input event to not be consumed here to end the ripple + // effect on the touched button. We will reset drag state in the ensuing + // onClick call that results. + return false; + } else { + mIsDragging = false; + return true; + } } } return true; @@ -824,16 +820,16 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { * @param scale the amount to scale to relative to the Screen Bounds */ private Rect calculateFreeformBounds(int displayId, float scale) { + // TODO(b/319819547): Account for app constraints so apps do not become letterboxed final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(displayId); final int screenWidth = displayLayout.width(); final int screenHeight = displayLayout.height(); final float adjustmentPercentage = (1f - scale) / 2; - final Rect endBounds = new Rect((int) (screenWidth * adjustmentPercentage), + return new Rect((int) (screenWidth * adjustmentPercentage), (int) (screenHeight * adjustmentPercentage), (int) (screenWidth * (adjustmentPercentage + scale)), (int) (screenHeight * (adjustmentPercentage + scale))); - return endBounds; } /** @@ -875,7 +871,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { c -> { c.onDragPositioningEndThroughStatusBar(relevantDecor.mTaskInfo, calculateFreeformBounds(ev.getDisplayId(), - FINAL_FREEFORM_SCALE)); + DesktopTasksController + .DESKTOP_MODE_INITIAL_BOUNDS_SCALE)); }); } }); diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt index adf92d8854ff..3380adac0b3f 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.appcompat import android.content.Context -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.FlickerTestData -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.FlickerTestData +import android.tools.flicker.legacy.LegacyFlickerTest import com.android.server.wm.flicker.helpers.LetterboxAppHelper import com.android.server.wm.flicker.helpers.setRotation import com.android.wm.shell.flicker.BaseTest diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt index 1e5e42fb077e..f08eba5a73a3 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt @@ -17,12 +17,12 @@ package com.android.wm.shell.flicker.appcompat import android.platform.test.annotations.Postsubmit -import android.tools.common.flicker.assertions.FlickerTest -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.assertions.FlickerTest +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt index 2fa1ec386781..826fc541687e 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt @@ -17,13 +17,13 @@ package com.android.wm.shell.flicker.appcompat import android.platform.test.annotations.Postsubmit -import android.tools.common.Rotation -import android.tools.common.flicker.assertions.FlickerTest -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.assertions.FlickerTest +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt index b74aa1d7bf73..26e78bf625ba 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt @@ -18,15 +18,15 @@ package com.android.wm.shell.flicker.appcompat import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.RequiresDevice -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.datatypes.Rect -import android.tools.common.flicker.assertions.FlickerTest -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.Rotation +import android.tools.datatypes.Rect +import android.tools.flicker.assertions.FlickerTest +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt index 68fa8d2fc2e8..2aa84b4e55b8 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt @@ -17,13 +17,13 @@ package com.android.wm.shell.flicker.appcompat import android.platform.test.annotations.Postsubmit -import android.tools.common.Rotation -import android.tools.common.flicker.assertions.FlickerTest -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.WindowUtils +import android.tools.Rotation +import android.tools.flicker.assertions.FlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.WindowUtils import androidx.test.filters.RequiresDevice import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt index fcb6931af9a2..443fac19c7e7 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt @@ -17,12 +17,12 @@ package com.android.wm.shell.flicker.appcompat import android.platform.test.annotations.Postsubmit -import android.tools.common.flicker.assertions.FlickerTest -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.WindowUtils +import android.tools.flicker.assertions.FlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.WindowUtils import androidx.test.filters.RequiresDevice import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt index 446aad8a8936..7ffa23345589 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt @@ -19,17 +19,17 @@ package com.android.wm.shell.flicker.appcompat import android.os.Build import android.platform.test.annotations.Postsubmit import android.system.helpers.CommandsHelper -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.datatypes.Rect -import android.tools.common.flicker.assertions.FlickerTest -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.FIND_TIMEOUT -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.NavBar +import android.tools.Rotation +import android.tools.datatypes.Rect +import android.tools.flicker.assertions.FlickerTest +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.FIND_TIMEOUT +import android.tools.traces.parsers.toFlickerComponent import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt index 9792c859cced..2c0f837248f7 100644 --- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt +++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.appcompat import android.content.Context -import android.tools.device.flicker.legacy.FlickerTestData -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.helpers.FIND_TIMEOUT -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.flicker.legacy.FlickerTestData +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.helpers.FIND_TIMEOUT +import android.tools.traces.parsers.toFlickerComponent import androidx.test.uiautomator.By import androidx.test.uiautomator.UiObject2 import androidx.test.uiautomator.Until diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt index 0c36e29a8315..8eca45694d48 100644 --- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt @@ -21,12 +21,12 @@ import android.app.NotificationManager import android.content.Context import android.content.pm.PackageManager import android.os.ServiceManager -import android.tools.common.Rotation -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.FlickerTestData -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.SYSTEMUI_PACKAGE +import android.tools.Rotation +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.FlickerTestData +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.SYSTEMUI_PACKAGE import androidx.test.uiautomator.By import androidx.test.uiautomator.UiObject2 import androidx.test.uiautomator.Until diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt index 55039f59190b..bc486c277aa5 100644 --- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt @@ -18,9 +18,9 @@ package com.android.wm.shell.flicker.bubble import android.os.SystemClock import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import androidx.test.filters.FlakyTest import androidx.test.uiautomator.By import androidx.test.uiautomator.UiObject2 diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt index 9ca7bf113589..521c0d0aaeb7 100644 --- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt @@ -19,11 +19,11 @@ package com.android.wm.shell.flicker.bubble import android.content.Context import android.graphics.Point import android.platform.test.annotations.Presubmit -import android.tools.common.flicker.subject.layers.LayersTraceSubject -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.subject.layers.LayersTraceSubject +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import android.util.DisplayMetrics import android.view.WindowManager import androidx.test.uiautomator.By diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt index b007e6b3535c..e059ac78dc6b 100644 --- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.bubble import android.platform.test.annotations.Postsubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import android.view.WindowInsets import android.view.WindowManager import androidx.test.filters.FlakyTest diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt index 4959672d865b..ef7fbfb79beb 100644 --- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt @@ -17,9 +17,9 @@ package com.android.wm.shell.flicker.bubble import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt index 0d95574aca06..87224b151b78 100644 --- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt @@ -17,9 +17,9 @@ package com.android.wm.shell.flicker.bubble import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt index af2db12faf3a..d64bfed382b9 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt @@ -17,9 +17,9 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.pip.common.EnterPipTransition @@ -46,7 +46,7 @@ import org.junit.runners.Parameterized * ``` * 1. All assertions are inherited from [EnterPipTest] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt index 8c0a524cda1e..a0edcfb17971 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -44,7 +44,7 @@ import org.junit.runners.Parameterized * ``` * 1. All assertions are inherited from [AutoEnterPipOnGoToHomeTest] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt index 9256725c6180..031acf4919eb 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import com.android.wm.shell.flicker.pip.common.ClosePipTransition import org.junit.FixMethodOrder import org.junit.Test @@ -44,7 +44,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt index 002c019eff93..860307f2bb76 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt @@ -17,9 +17,9 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import com.android.wm.shell.flicker.pip.common.ClosePipTransition import org.junit.FixMethodOrder import org.junit.Test @@ -44,7 +44,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt index 4cc9547ba2e3..c5541613fece 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt @@ -17,9 +17,9 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import com.android.wm.shell.flicker.pip.common.EnterPipTransition import org.junit.Assume import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt index 07cd68261083..9a1bd267ea1f 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt @@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.pip import android.app.Activity import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.flicker.assertions.FlickerTest -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.WindowUtils +import android.tools.Rotation +import android.tools.flicker.assertions.FlickerTest +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.WindowUtils import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper @@ -60,7 +60,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` @@ -206,6 +206,18 @@ class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(fli } } + @Presubmit + @Test + fun pipLayerRemainInsideVisibleBounds() { + // during the transition we assert the center point is within the display bounds, since it + // might go outside of bounds as we resize from landscape fullscreen to destination bounds, + // and once the animation is over we assert that it's fully within the display bounds, at + // which point the device also performs orientation change from landscape to portrait + flicker.assertLayersVisibleRegion(pipApp.or(ComponentNameMatcher.PIP_CONTENT_OVERLAY)) { + regionsCenterPointInside(startingBounds).then().coversAtMost(endingBounds) + } + } + /** {@inheritDoc} */ @FlakyTest(bugId = 267424412) @Test diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt index cc943678d492..f97d8d1842b0 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt @@ -16,9 +16,9 @@ package com.android.wm.shell.flicker.pip -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import com.android.wm.shell.flicker.pip.common.EnterPipTransition import org.junit.FixMethodOrder import org.junit.runner.RunWith @@ -41,7 +41,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited from [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt index 7da442901e40..47bf41814d17 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt @@ -16,9 +16,9 @@ package com.android.wm.shell.flicker.pip -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition import org.junit.FixMethodOrder import org.junit.runner.RunWith @@ -43,7 +43,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt index 0ad9e4c61d83..a356e68d14dd 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt @@ -16,9 +16,9 @@ package com.android.wm.shell.flicker.pip -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition import org.junit.FixMethodOrder import org.junit.runner.RunWith @@ -42,7 +42,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited from [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt index 89a6c93e478c..25614ef63ccc 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt @@ -17,12 +17,12 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test @@ -46,7 +46,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt index 8978af0088b8..1964e3cebc89 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt index 27922988038c..b94989d98e97 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt @@ -17,13 +17,13 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.WindowUtils -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.WindowUtils +import android.tools.traces.parsers.toFlickerComponent import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions @@ -52,7 +52,7 @@ import org.junit.runners.Parameterized * ``` * 1. All assertions are inherited from [EnterPipTest] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt index 4c2315324eca..1ccc7d8084a6 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt @@ -17,13 +17,13 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.WindowUtils -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.WindowUtils +import android.tools.traces.parsers.toFlickerComponent import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions @@ -53,7 +53,7 @@ import org.junit.runners.Parameterized * ``` * 1. All assertions are inherited from [EnterPipTest] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt index 4776206724cc..9b746224a1a0 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt @@ -17,9 +17,9 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition import com.android.wm.shell.flicker.utils.Direction @@ -47,7 +47,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt index 425cbfaffedd..e184cf04e4ae 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt @@ -17,14 +17,14 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.flicker.assertions.FlickerTest -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.WindowUtils +import android.tools.Rotation +import android.tools.flicker.assertions.FlickerTest +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.WindowUtils import com.android.server.wm.flicker.helpers.ImeAppHelper import com.android.server.wm.flicker.helpers.setRotation import com.android.wm.shell.flicker.pip.common.PipTransition diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt index 18f30d96938b..490ebd190ee8 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt @@ -17,9 +17,9 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition import com.android.wm.shell.flicker.utils.Direction @@ -47,7 +47,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt index 36047cca55ea..70be58f06548 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt index c7f2786debd0..a4df69fc6539 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt @@ -18,10 +18,10 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit import android.platform.test.annotations.RequiresDevice -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import com.android.server.wm.flicker.testapp.ActivityOptions import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt index cabc1cc0b023..90b9798c6329 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt @@ -17,12 +17,12 @@ package com.android.wm.shell.flicker.pip import android.graphics.Rect -import android.tools.common.Rotation -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.rules.RemoveAllTasksButHomeRule import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.setRotation diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt index 381f947cbc84..68417066ac0a 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt @@ -17,12 +17,12 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.flicker.subject.exceptions.IncorrectRegionException -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.subject.exceptions.IncorrectRegionException +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt index 1f69847e5481..9a6dacb187ef 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt @@ -19,13 +19,13 @@ package com.android.wm.shell.flicker.pip import android.app.Activity import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.flicker.assertions.FlickerTest -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.WindowUtils +import android.tools.Rotation +import android.tools.flicker.assertions.FlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.WindowUtils import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt index 308ece40402f..d2f803ec9352 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt @@ -17,12 +17,12 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit -import android.tools.common.flicker.assertions.FlickerTest -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.WindowUtils +import android.tools.flicker.assertions.FlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.WindowUtils import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.helpers.setRotation import com.android.wm.shell.flicker.pip.common.PipTransition @@ -50,7 +50,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited from [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt index be771712834f..c9f4a6ca75b1 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt @@ -17,13 +17,13 @@ package com.android.wm.shell.flicker.pip.apps import android.platform.test.annotations.Postsubmit -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.Rotation +import android.tools.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.flicker.junit.FlickerBuilderProvider -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerBuilderProvider +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import com.android.wm.shell.flicker.pip.common.EnterPipTransition import org.junit.Test import org.junit.runners.Parameterized @@ -101,8 +101,9 @@ abstract class AppsEnterPipTransition(flicker: LegacyFlickerTest) : EnterPipTran override fun pipLayerReduces() { flicker.assertLayers { val pipLayerList = - this.layers { standardAppHelper.packageNameMatcher.layerMatchesAnyOf(it) - && it.isVisible } + this.layers { + standardAppHelper.packageNameMatcher.layerMatchesAnyOf(it) && it.isVisible + } pipLayerList.zipWithNext { previous, current -> current.visibleRegion.notBiggerThan(previous.visibleRegion.region) } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt index 4c2eff3b6ce4..88650107e63a 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt @@ -26,9 +26,9 @@ import android.os.Looper import android.os.SystemClock import android.platform.test.annotations.Postsubmit import android.tools.device.apphelpers.MapsAppHelper -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import androidx.test.filters.RequiresDevice import org.junit.Assume import org.junit.FixMethodOrder @@ -53,7 +53,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited from [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt index 143f7a726ed3..9b5153875987 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt @@ -18,14 +18,14 @@ package com.android.wm.shell.flicker.pip.apps import android.Manifest import android.platform.test.annotations.Postsubmit -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.NavBar +import android.tools.Rotation +import android.tools.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.NetflixAppHelper -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.statusBarLayerPositionAtEnd import org.junit.Assume @@ -51,7 +51,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited from [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt index 509b32c11afe..3ae5937df4d0 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt @@ -18,11 +18,11 @@ package com.android.wm.shell.flicker.pip.apps import android.Manifest import android.platform.test.annotations.Postsubmit -import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.YouTubeAppHelper -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import androidx.test.filters.RequiresDevice import org.junit.Assume import org.junit.FixMethodOrder @@ -47,7 +47,7 @@ import org.junit.runners.Parameterized * 1. Some default assertions (e.g., nav bar, status bar and screen covered) * are inherited from [PipTransition] * 2. Part of the test setup occurs automatically via - * [android.tools.device.flicker.legacy.runner.TransitionRunner], + * [android.tools.flicker.legacy.runner.TransitionRunner], * including configuring navigation mode, initial orientation and ensuring no * apps are running before setup * ``` diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt index 751f2bc0807f..dc122590388f 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.pip.common import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.traces.component.ComponentNameMatcher.Companion.LAUNCHER +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import com.android.server.wm.flicker.helpers.setRotation import org.junit.Test import org.junit.runners.Parameterized diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt index 9c129e47efba..3d9eae62b499 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.pip.common import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import org.junit.Test import org.junit.runners.Parameterized diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt index 9450bdd2d894..7b6839dc123f 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.pip.common import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import com.android.server.wm.flicker.helpers.SimpleAppHelper import org.junit.Test import org.junit.runners.Parameterized diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt index 7e42bc11a9c1..f4baf5f75928 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.pip.common import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.flicker.subject.region.RegionSubject -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.subject.region.RegionSubject +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper import com.android.wm.shell.flicker.utils.Direction import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt index 7b7f1d7b5a82..fd467e32e0dc 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt @@ -19,12 +19,12 @@ package com.android.wm.shell.flicker.pip.common import android.app.Instrumentation import android.content.Intent import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome -import android.tools.device.helpers.WindowUtils +import android.tools.Rotation +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome +import android.tools.helpers.WindowUtils import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt index c6cbcd052fe0..4e1a8ff313cc 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt @@ -17,7 +17,7 @@ package com.android.wm.shell.flicker.pip.tv import android.app.Instrumentation -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.uiautomator.By import androidx.test.uiautomator.BySelector import androidx.test.uiautomator.UiObject2 diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt index 0d1853534927..285422236c64 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt @@ -20,8 +20,8 @@ import android.app.ActivityManager import android.app.IActivityManager import android.app.IProcessObserver import android.os.SystemClock -import android.tools.device.helpers.wakeUpAndGoToHomeScreen -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.helpers.wakeUpAndGoToHomeScreen +import android.tools.traces.parsers.WindowManagerStateHelper import android.view.Surface.ROTATION_0 import android.view.Surface.rotationToString import com.android.wm.shell.flicker.utils.SYSTEM_UI_PACKAGE_NAME diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt index 4bd79546b96d..4c6c6cce0105 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt @@ -20,13 +20,13 @@ import android.app.Instrumentation import android.platform.test.rule.NavigationModeRule import android.platform.test.rule.PressHomeRule import android.platform.test.rule.UnlockScreenRule -import android.tools.common.NavBar -import android.tools.common.Rotation +import android.tools.NavBar +import android.tools.Rotation import android.tools.device.apphelpers.MessagingAppHelper -import android.tools.device.flicker.rules.ArtifactSaverRule -import android.tools.device.flicker.rules.ChangeDisplayOrientationRule -import android.tools.device.flicker.rules.LaunchAppRule -import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule +import android.tools.flicker.rules.ArtifactSaverRule +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.flicker.rules.LaunchAppRule +import android.tools.flicker.rules.RemoveAllTasksButHomeRule import androidx.test.platform.app.InstrumentationRegistry import org.junit.rules.RuleChain diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt index a5c512267508..1684a26ac3d2 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt index 092fb6720e57..3b5fad60d8ee 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt index 69499b9b488b..2b8a90305d90 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt index bd627f4babaa..b284fe1caad5 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt index a8f4d0a24c7e..a400ee44caa5 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt index cee9bbfb4aa4..7f5ee4c2cdda 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt index c1b3aade11cd..1b075c498bc0 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt index c6e2e854ab89..6ca373714f8a 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt index 169b5cfa3462..f7d231f02935 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt index 412c011a3f17..ab819fad292a 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt index 6e4cf9f55cfd..a6b732c47ea2 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt index cc2870213e8d..07e5f4b0b472 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt index 736604f02377..272569456d7b 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt index 8df8dfaab071..58cc4d70fde4 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt index 378f055ef830..85897a136e33 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt index b33d26288d33..891b6df89b45 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt index b1d3858b9dbb..798365218b04 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt index 6d824c74c1fe..1bdea66fc596 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt index f1d3d0cf2716..bab0c0aa1e6a 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt index a867bac8c0eb..17a59ab8a173 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt index 76247ba10037..2c36d647b719 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt index e179da81e4db..6e91d047e64b 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt index 20f554f7d154..a921b4663d09 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt index f7776ee3244a..05f8912f6f47 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt index 4ff0b4362e60..1ae1f53b9bc1 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt index 930f31d1f348..e14ca550c84d 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt index 3da61e5e310c..ce0c4c456587 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt index 627ae1843314..5a8d2d51bec4 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt index c744103d49ba..d44261549544 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt @@ -16,12 +16,12 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt index 11a4e02c5e37..ddc8a0697beb 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt @@ -16,12 +16,12 @@ package com.android.wm.shell.flicker.service.splitscreen.flicker -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen import org.junit.Test import org.junit.runner.RunWith diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt index e37d806c7a14..64293b288a2e 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt index 2a50912e0a5c..517ba2dfc164 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt index d5da1a8b558c..1bafe3b0898c 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt index 7fdcb9be62ee..fd0100fd6c21 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt index 308e954b86c1..850b3d8f9867 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt index 39e75bd25a71..0b752bf7f58e 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt index e18da17175c0..3c52aa71eb9d 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt index 00d60e756ffa..c2e21b89a480 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt index d7efbc8c0fd4..bf85ab44df5e 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt index 4eece3f62d10..0ac4ca20e303 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt index d96b056d8753..80bd088a192f 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt index 809b690e0861..0dffb4af8d41 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt index bbdf2d728494..b721f2fe294a 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt index 5c29fd8fe57e..22cbc77d024b 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt index a7398ebf56e8..ac0f9e25285d 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt index eae88ad4ad09..f7a229d5ff16 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt index 7e8ee04a28fa..6dbbcb0fcfb5 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt index 9295c330b879..bd69ea98a67b 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt index 4b59e9fbd866..404b96fafd24 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt index 5ff36d4aabbb..a79687ddf68f 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt index c0cb7219437b..b52eb4cd6533 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt index 8c140884aa50..d79620c73132 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt index 7b6614b81c11..d27bfa1a22c9 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt index 5df5be9daa8b..3c7d4d4806cf 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt index 9d63003bf2a1..26a2034f16d9 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt index 9fa04b208ad1..5154b35ed0e6 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt index 9386aa2b2cf0..86451c524ee6 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt index 5ef21672bfe0..baf72b40d6d4 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.service.splitscreen.platinum import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation +import android.tools.Rotation import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs import org.junit.Test diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt index 824e45403d2a..89ef91e12758 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.AndroidLoggerSetupRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.AndroidLoggerSetupRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt index 4c391047e853..c1a8ee714abd 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt @@ -17,9 +17,9 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt index f6d1afc05a5a..600855a8ab38 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt @@ -17,9 +17,9 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt index db5a32a382fb..c671fbe39ac5 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt @@ -17,9 +17,9 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt index 03170a326890..a189325d52ea 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.flicker.rules.ChangeDisplayOrientationRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt index c52ada3b312f..433669205834 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.AndroidLoggerSetupRule -import android.tools.device.flicker.rules.ChangeDisplayOrientationRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.AndroidLoggerSetupRule +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt index 479d01ddaeb9..8c7e63f7471f 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.AndroidLoggerSetupRule -import android.tools.device.flicker.rules.ChangeDisplayOrientationRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.AndroidLoggerSetupRule +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt index 625c56bc4a4c..2072831d7d1b 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.AndroidLoggerSetupRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.AndroidLoggerSetupRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt index f1a011c0d191..09e77ccffba7 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.AndroidLoggerSetupRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.AndroidLoggerSetupRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt index c9b1c916ff4b..babdae164835 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt @@ -18,11 +18,11 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation import android.graphics.Point -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.AndroidLoggerSetupRule -import android.tools.device.helpers.WindowUtils -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.AndroidLoggerSetupRule +import android.tools.helpers.WindowUtils +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt index 72f2db3380dd..3e8547961ea0 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.AndroidLoggerSetupRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.AndroidLoggerSetupRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt index 511de4fd8b90..655ae4e29af3 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.AndroidLoggerSetupRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.AndroidLoggerSetupRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt index 558d2bf1f349..22082586bb62 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.AndroidLoggerSetupRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.AndroidLoggerSetupRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt index ecd68295df9a..2ac63c2afefc 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.AndroidLoggerSetupRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.AndroidLoggerSetupRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt index f50d5c7df8d7..35b122d7bc9e 100644 --- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.service.splitscreen.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.AndroidLoggerSetupRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.AndroidLoggerSetupRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt index 6b971699d212..d74c59ef0879 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt @@ -17,12 +17,12 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.common.traces.component.EdgeExtensionComponentMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.component.EdgeExtensionComponentMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.CopyContentInSplitBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt index 51588569a8aa..dd45f654d3bc 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt @@ -18,10 +18,10 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.helpers.WindowUtils +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.helpers.WindowUtils import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByDividerBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt index fc6c2b3d7ce7..6d396ea6e9d4 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByGoHomeBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt index 8b1689a9d816..2ed916e56c67 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.DragDividerToResizeBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt index 99613f39060d..1a455311b3b6 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt @@ -18,11 +18,11 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromAllAppsBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt index 756a7fa4ba98..0cb1e4006c0d 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt @@ -18,11 +18,11 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromNotificationBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt index 121b46acdb66..ff406b75b235 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromShortcutBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt index 99deb9279271..2b817988a589 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt @@ -18,11 +18,11 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromTaskbarBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt index 212a4e3649dc..186af54fb57b 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenFromOverviewBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt index fac97c8cc8c4..9dde49011ed0 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt @@ -18,11 +18,11 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchAppByDoubleTapDividerBenchmark import com.android.wm.shell.flicker.utils.ICommonAssertions diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt index 284c32ea110d..5222b08240c6 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromAnotherAppBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt index 9e6448f0bec9..a8a8ae88a9e7 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromHomeBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt index 8e28712cd993..836f664ca544 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt @@ -17,11 +17,11 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromRecentBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt index fb0193b1830d..3c4a1caecb8d 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt @@ -17,10 +17,10 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBetweenSplitPairsBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt index 715a533a7bab..8724346427f4 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt @@ -17,12 +17,12 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.PipAppHelper import com.android.wm.shell.flicker.splitscreen.benchmark.SplitScreenBase diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt index e6a2022166ea..16d73318bd3a 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt @@ -18,14 +18,14 @@ package com.android.wm.shell.flicker.splitscreen import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.common.flicker.subject.layers.LayersTraceSubject -import android.tools.common.flicker.subject.region.RegionSubject -import android.tools.common.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.subject.layers.LayersTraceSubject +import android.tools.flicker.subject.region.RegionSubject +import android.tools.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.splitscreen.benchmark.UnlockKeyguardToSplitScreenBenchmark diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt index df1c9a2ec089..9c5a3fe35bfe 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt @@ -16,11 +16,11 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt index d01eab060263..c99fcc4129d5 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt @@ -16,10 +16,10 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt index e36bd33bd1fd..ef3a87955bd6 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt @@ -16,10 +16,10 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt index 050d389e978c..18550d7f0467 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt @@ -16,10 +16,10 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.Assume diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt index 5c43cbdb3832..d16c5d77410c 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt @@ -16,11 +16,11 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.After diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt index cd3fbab1497b..f8be6be08782 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt @@ -16,11 +16,11 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.Assume diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt index 15ad0c12c49a..a99ef64e7bf5 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt @@ -16,11 +16,11 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.After diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt index ca8adb1fcb38..f58400966531 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt @@ -16,11 +16,11 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.After diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt index 5e5e7d7fc3c9..7084f6aec1fb 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt @@ -16,10 +16,10 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt index a0e437c25aa7..4b106034b2b5 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt @@ -17,8 +17,8 @@ package com.android.wm.shell.flicker.splitscreen.benchmark import android.content.Context -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import com.android.server.wm.flicker.helpers.setRotation import com.android.wm.shell.flicker.BaseBenchmarkTest import com.android.wm.shell.flicker.utils.SplitScreenUtils diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt index e39c3c93d79a..38206c396efb 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt @@ -16,14 +16,14 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.WindowUtils -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.WindowUtils +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt index 32284ba41aee..3a2316f7a10c 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt @@ -16,11 +16,11 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt index a926ec903f58..ded0b0729998 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt @@ -16,11 +16,11 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt index d2e1d5294aa1..7b1397baa7a3 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt @@ -16,11 +16,11 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt index 9d6b25174c13..457288f445df 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt @@ -16,10 +16,10 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt index e71834de7123..7493538fa2ba 100644 --- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt +++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt @@ -16,11 +16,11 @@ package com.android.wm.shell.flicker.splitscreen.benchmark -import android.tools.common.NavBar -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.FixMethodOrder diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt index e9363f725fd8..d03c2f1077bd 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt @@ -17,9 +17,9 @@ package com.android.wm.shell.flicker import android.app.Instrumentation -import android.tools.device.flicker.junit.FlickerBuilderProvider -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerBuilderProvider +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt index 568650d71872..a19d232c9a2f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt @@ -17,8 +17,8 @@ package com.android.wm.shell.flicker import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.legacy.LegacyFlickerTest import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.tapl.LauncherInstrumentation import com.android.wm.shell.flicker.utils.ICommonAssertions diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt index f1cb37ee1293..3df0954da2e9 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt @@ -18,13 +18,13 @@ package com.android.wm.shell.flicker.utils -import android.tools.common.Rotation -import android.tools.common.datatypes.Region -import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject -import android.tools.common.flicker.subject.layers.LayersTraceSubject -import android.tools.common.traces.component.IComponentMatcher -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.helpers.WindowUtils +import android.tools.Rotation +import android.tools.datatypes.Region +import android.tools.flicker.subject.layers.LayerTraceEntrySubject +import android.tools.flicker.subject.layers.LayersTraceSubject +import android.tools.traces.component.IComponentMatcher +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.helpers.WindowUtils fun LegacyFlickerTest.appPairsDividerIsVisibleAtEnd() { assertLayersEnd { this.isVisible(APP_PAIR_SPLIT_DIVIDER_COMPONENT) } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt index 3b66d6addacd..fb21fcceea6e 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt @@ -18,7 +18,7 @@ package com.android.wm.shell.flicker.utils -import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.traces.component.ComponentNameMatcher const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui" const val LAUNCHER_UI_PACKAGE_NAME = "com.google.android.apps.nexuslauncher" diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt index 7f58cedce63d..50c04354528f 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt @@ -17,8 +17,8 @@ package com.android.wm.shell.flicker.utils import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher +import android.tools.flicker.legacy.LegacyFlickerTest import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt index 3244ebc9ef32..4e9a9d65dbf9 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt @@ -19,14 +19,14 @@ package com.android.wm.shell.flicker.utils import android.app.Instrumentation import android.graphics.Point import android.os.SystemClock -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.common.traces.component.IComponentMatcher -import android.tools.common.traces.component.IComponentNameMatcher +import android.tools.Rotation +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.component.IComponentMatcher +import android.tools.traces.component.IComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.flicker.rules.ChangeDisplayOrientationRule -import android.tools.device.traces.parsers.WindowManagerStateHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.toFlickerComponent import android.view.InputDevice import android.view.MotionEvent import android.view.ViewConfiguration diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp index 8c4711603904..32c070305e05 100644 --- a/libs/WindowManager/Shell/tests/unittest/Android.bp +++ b/libs/WindowManager/Shell/tests/unittest/Android.bp @@ -24,7 +24,10 @@ package { android_test { name: "WMShellUnitTests", - + defaults: [ + // For ExtendedMockito dependencies. + "modules-utils-testable-device-config-defaults", + ], srcs: [ "**/*.java", "**/*.kt", diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt new file mode 100644 index 000000000000..4548fcb06c55 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.desktopmode + +import com.android.dx.mockito.inline.extended.ExtendedMockito +import com.android.internal.util.FrameworkStatsLog +import com.android.modules.utils.testing.ExtendedMockitoRule +import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason +import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason +import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate +import kotlinx.coroutines.runBlocking +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mockito.kotlin.eq + +/** + * Tests for [DesktopModeEventLogger]. + */ +class DesktopModeEventLoggerTest { + + private val desktopModeEventLogger = DesktopModeEventLogger() + + @JvmField + @Rule + val extendedMockitoRule = ExtendedMockitoRule.Builder(this) + .mockStatic(FrameworkStatsLog::class.java).build()!! + + @Test + fun logSessionEnter_enterReason() = runBlocking { + desktopModeEventLogger.logSessionEnter(sessionId = SESSION_ID, EnterReason.UNKNOWN_ENTER) + + ExtendedMockito.verify { + FrameworkStatsLog.write( + eq(FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED), + /* event */ + eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__ENTER), + /* enter_reason */ + eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__UNKNOWN_ENTER), + /* exit_reason */ + eq(0), + /* sessionId */ + eq(SESSION_ID) + ) + } + } + + @Test + fun logSessionExit_exitReason() = runBlocking { + desktopModeEventLogger.logSessionExit(sessionId = SESSION_ID, ExitReason.UNKNOWN_EXIT) + + ExtendedMockito.verify { + FrameworkStatsLog.write( + eq(FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED), + /* event */ + eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__EXIT), + /* enter_reason */ + eq(0), + /* exit_reason */ + eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__UNKNOWN_EXIT), + /* sessionId */ + eq(SESSION_ID) + ) + } + } + + @Test + fun logTaskAdded_taskUpdate() = runBlocking { + desktopModeEventLogger.logTaskAdded(sessionId = SESSION_ID, TASK_UPDATE) + + ExtendedMockito.verify { + FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE), + /* task_event */ + eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_ADDED), + /* instance_id */ + eq(TASK_UPDATE.instanceId), + /* uid */ + eq(TASK_UPDATE.uid), + /* task_height */ + eq(TASK_UPDATE.taskHeight), + /* task_width */ + eq(TASK_UPDATE.taskWidth), + /* task_x */ + eq(TASK_UPDATE.taskX), + /* task_y */ + eq(TASK_UPDATE.taskY), + /* session_id */ + eq(SESSION_ID)) + } + } + + @Test + fun logTaskRemoved_taskUpdate() = runBlocking { + desktopModeEventLogger.logTaskRemoved(sessionId = SESSION_ID, TASK_UPDATE) + + ExtendedMockito.verify { + FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE), + /* task_event */ + eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_REMOVED), + /* instance_id */ + eq(TASK_UPDATE.instanceId), + /* uid */ + eq(TASK_UPDATE.uid), + /* task_height */ + eq(TASK_UPDATE.taskHeight), + /* task_width */ + eq(TASK_UPDATE.taskWidth), + /* task_x */ + eq(TASK_UPDATE.taskX), + /* task_y */ + eq(TASK_UPDATE.taskY), + /* session_id */ + eq(SESSION_ID)) + } + } + + @Test + fun logTaskInfoChanged_taskUpdate() = runBlocking { + desktopModeEventLogger.logTaskInfoChanged(sessionId = SESSION_ID, TASK_UPDATE) + + ExtendedMockito.verify { + FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE), + /* task_event */ + eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED), + /* instance_id */ + eq(TASK_UPDATE.instanceId), + /* uid */ + eq(TASK_UPDATE.uid), + /* task_height */ + eq(TASK_UPDATE.taskHeight), + /* task_width */ + eq(TASK_UPDATE.taskWidth), + /* task_x */ + eq(TASK_UPDATE.taskX), + /* task_y */ + eq(TASK_UPDATE.taskY), + /* session_id */ + eq(SESSION_ID)) + } + } + + companion object { + private const val SESSION_ID = 1 + private const val TASK_ID = 1 + private const val TASK_UID = 1 + private const val TASK_X = 0 + private const val TASK_Y = 0 + private const val TASK_HEIGHT = 100 + private const val TASK_WIDTH = 100 + + private val TASK_UPDATE = TaskUpdate( + TASK_ID, TASK_UID, TASK_HEIGHT, TASK_WIDTH, TASK_X, TASK_Y + ) + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt index 383621beca22..35c803b78674 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt @@ -781,6 +781,23 @@ class DesktopTasksControllerTest : ShellTestCase() { ) } + @Test + fun moveFocusedTaskToFullscreen() { + val task1 = setUpFreeformTask() + val task2 = setUpFreeformTask() + val task3 = setUpFreeformTask() + + task1.isFocused = false + task2.isFocused = true + task3.isFocused = false + + controller.enterFullscreen(DEFAULT_DISPLAY) + + val wct = getLatestExitDesktopWct() + assertThat(wct.changes[task2.token.asBinder()]?.windowingMode) + .isEqualTo(WINDOWING_MODE_FULLSCREEN) + } + private fun setUpFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo { val task = createFreeformTask(displayId) whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java index 1b347e01888e..5dd9d8a859d6 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropPolicyTest.java @@ -22,9 +22,11 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.ClipDescription.MIMETYPE_APPLICATION_ACTIVITY; import static android.content.ClipDescription.MIMETYPE_APPLICATION_SHORTCUT; import static android.content.ClipDescription.MIMETYPE_APPLICATION_TASK; +import static android.content.ClipDescription.MIMETYPE_TEXT_INTENT; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED; @@ -46,6 +48,8 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.quality.Strictness.LENIENT; import android.app.ActivityManager; import android.app.ActivityTaskManager; @@ -61,6 +65,7 @@ import android.content.res.Resources; import android.graphics.Insets; import android.os.RemoteException; import android.view.DisplayInfo; +import android.view.DragEvent; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -70,12 +75,15 @@ import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target; import com.android.wm.shell.splitscreen.SplitScreenController; +import com.android.wm.shell.startingsurface.TaskSnapshotWindow; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.mockito.MockitoSession; import java.util.ArrayList; import java.util.Collections; @@ -107,6 +115,7 @@ public class DragAndDropPolicyTest extends ShellTestCase { private DragAndDropPolicy mPolicy; private ClipData mActivityClipData; + private ClipData mLaunchableIntentClipData; private ClipData mNonResizeableActivityClipData; private ClipData mTaskClipData; private ClipData mShortcutClipData; @@ -115,9 +124,16 @@ public class DragAndDropPolicyTest extends ShellTestCase { private ActivityManager.RunningTaskInfo mFullscreenAppTask; private ActivityManager.RunningTaskInfo mNonResizeableFullscreenAppTask; + private MockitoSession mMockitoSession; + @Before public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); + mMockitoSession = mockitoSession() + .strictness(LENIENT) + .mockStatic(DragUtils.class) + .startMocking(); + when(DragUtils.canHandleDrag(any())).thenReturn(true); Resources res = mock(Resources.class); Configuration config = new Configuration(); @@ -134,11 +150,12 @@ public class DragAndDropPolicyTest extends ShellTestCase { mInsets = Insets.of(0, 0, 0, 0); mPolicy = spy(new DragAndDropPolicy(mContext, mSplitScreenStarter, mSplitScreenStarter)); - mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY); - mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY); + mActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY); + mLaunchableIntentClipData = createIntentClipData(); + mNonResizeableActivityClipData = createAppClipData(MIMETYPE_APPLICATION_ACTIVITY); setClipDataResizeable(mNonResizeableActivityClipData, false); - mTaskClipData = createClipData(MIMETYPE_APPLICATION_TASK); - mShortcutClipData = createClipData(MIMETYPE_APPLICATION_SHORTCUT); + mTaskClipData = createAppClipData(MIMETYPE_APPLICATION_TASK); + mShortcutClipData = createAppClipData(MIMETYPE_APPLICATION_SHORTCUT); mHomeTask = createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME); mFullscreenAppTask = createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); @@ -149,10 +166,15 @@ public class DragAndDropPolicyTest extends ShellTestCase { setRunningTask(mFullscreenAppTask); } + @After + public void tearDown() { + mMockitoSession.finishMocking(); + } + /** - * Creates a clip data that is by default resizeable. + * Creates an app-based clip data that is by default resizeable. */ - private ClipData createClipData(String mimeType) { + private ClipData createAppClipData(String mimeType) { ClipDescription clipDescription = new ClipDescription(mimeType, new String[] { mimeType }); Intent i = new Intent(); switch (mimeType) { @@ -164,7 +186,9 @@ public class DragAndDropPolicyTest extends ShellTestCase { i.putExtra(Intent.EXTRA_TASK_ID, 12345); break; case MIMETYPE_APPLICATION_ACTIVITY: - i.putExtra(ClipDescription.EXTRA_PENDING_INTENT, mock(PendingIntent.class)); + final PendingIntent pi = mock(PendingIntent.class); + doReturn(android.os.Process.myUserHandle()).when(pi).getCreatorUserHandle(); + i.putExtra(ClipDescription.EXTRA_PENDING_INTENT, pi); break; } i.putExtra(Intent.EXTRA_USER, android.os.Process.myUserHandle()); @@ -175,6 +199,22 @@ public class DragAndDropPolicyTest extends ShellTestCase { return data; } + /** + * Creates an intent-based clip data that is by default resizeable. + */ + private ClipData createIntentClipData() { + ClipDescription clipDescription = new ClipDescription("Intent", + new String[] { MIMETYPE_TEXT_INTENT }); + PendingIntent intent = mock(PendingIntent.class); + when(intent.getCreatorUserHandle()).thenReturn(android.os.Process.myUserHandle()); + ClipData.Item item = new ClipData.Item.Builder() + .setIntentSender(intent.getIntentSender()) + .build(); + ClipData data = new ClipData(clipDescription, item); + when(DragUtils.getLaunchIntent((ClipData) any())).thenReturn(intent); + return data; + } + private ActivityManager.RunningTaskInfo createTaskInfo(int winMode, int actType) { ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo(); info.configuration.windowConfiguration.setActivityType(actType); @@ -204,58 +244,85 @@ public class DragAndDropPolicyTest extends ShellTestCase { @Test public void testDragAppOverFullscreenHome_expectOnlyFullscreenTarget() { + dragOverFullscreenHome_expectOnlyFullscreenTarget(mActivityClipData); + } + + @Test + public void testDragAppOverFullscreenApp_expectSplitScreenTargets() { + dragOverFullscreenApp_expectSplitScreenTargets(mActivityClipData); + } + + @Test + public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenTargets() { + dragOverFullscreenAppPhone_expectVerticalSplitScreenTargets(mActivityClipData); + } + + @Test + public void testDragIntentOverFullscreenHome_expectOnlyFullscreenTarget() { + dragOverFullscreenHome_expectOnlyFullscreenTarget(mLaunchableIntentClipData); + } + + @Test + public void testDragIntentOverFullscreenApp_expectSplitScreenTargets() { + dragOverFullscreenApp_expectSplitScreenTargets(mLaunchableIntentClipData); + } + + @Test + public void testDragIntentOverFullscreenAppPhone_expectVerticalSplitScreenTargets() { + dragOverFullscreenAppPhone_expectVerticalSplitScreenTargets(mLaunchableIntentClipData); + } + + private void dragOverFullscreenHome_expectOnlyFullscreenTarget(ClipData data) { doReturn(true).when(mSplitScreenStarter).isLeftRightSplit(); setRunningTask(mHomeTask); - DragSession dragSession = new DragSession(mContext, mActivityTaskManager, - mLandscapeDisplayLayout, mActivityClipData); + DragSession dragSession = new DragSession(mActivityTaskManager, + mLandscapeDisplayLayout, data); dragSession.update(); mPolicy.start(dragSession, mLoggerSessionId); ArrayList<Target> targets = assertExactTargetTypes( mPolicy.getTargets(mInsets), TYPE_FULLSCREEN); - mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); + mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN)); verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(), eq(SPLIT_POSITION_UNDEFINED), any()); } - @Test - public void testDragAppOverFullscreenApp_expectSplitScreenTargets() { + private void dragOverFullscreenApp_expectSplitScreenTargets(ClipData data) { doReturn(true).when(mSplitScreenStarter).isLeftRightSplit(); setRunningTask(mFullscreenAppTask); - DragSession dragSession = new DragSession(mContext, mActivityTaskManager, - mLandscapeDisplayLayout, mActivityClipData); + DragSession dragSession = new DragSession(mActivityTaskManager, + mLandscapeDisplayLayout, data); dragSession.update(); mPolicy.start(dragSession, mLoggerSessionId); ArrayList<Target> targets = assertExactTargetTypes( mPolicy.getTargets(mInsets), TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); - mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT), mActivityClipData); + mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_LEFT)); verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(), eq(SPLIT_POSITION_TOP_OR_LEFT), any()); reset(mSplitScreenStarter); - mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData); + mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT)); verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any()); } - @Test - public void testDragAppOverFullscreenAppPhone_expectVerticalSplitScreenTargets() { + private void dragOverFullscreenAppPhone_expectVerticalSplitScreenTargets(ClipData data) { doReturn(false).when(mSplitScreenStarter).isLeftRightSplit(); setRunningTask(mFullscreenAppTask); - DragSession dragSession = new DragSession(mContext, mActivityTaskManager, - mPortraitDisplayLayout, mActivityClipData); + DragSession dragSession = new DragSession(mActivityTaskManager, + mPortraitDisplayLayout, data); dragSession.update(); mPolicy.start(dragSession, mLoggerSessionId); ArrayList<Target> targets = assertExactTargetTypes( mPolicy.getTargets(mInsets), TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM); - mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP), mActivityClipData); + mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_TOP)); verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(), eq(SPLIT_POSITION_TOP_OR_LEFT), any()); reset(mSplitScreenStarter); - mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData); + mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM)); verify(mSplitScreenStarter).startIntent(any(), anyInt(), any(), eq(SPLIT_POSITION_BOTTOM_OR_RIGHT), any()); } @@ -263,7 +330,7 @@ public class DragAndDropPolicyTest extends ShellTestCase { @Test public void testTargetHitRects() { setRunningTask(mFullscreenAppTask); - DragSession dragSession = new DragSession(mContext, mActivityTaskManager, + DragSession dragSession = new DragSession(mActivityTaskManager, mLandscapeDisplayLayout, mActivityClipData); dragSession.update(); mPolicy.start(dragSession, mLoggerSessionId); diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in index d21f07efe36a..b12486e32bd4 100644 --- a/libs/hwui/DisplayListOps.in +++ b/libs/hwui/DisplayListOps.in @@ -26,6 +26,7 @@ X(ClipPath) X(ClipRect) X(ClipRRect) X(ClipRegion) +X(ClipShader) X(ResetClip) X(DrawPaint) X(DrawBehind) diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index 3b694c5d399b..54aef55f8b90 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -207,6 +207,13 @@ struct ClipRegion final : Op { SkClipOp op; void draw(SkCanvas* c, const SkMatrix&) const { c->clipRegion(region, op); } }; +struct ClipShader final : Op { + static const auto kType = Type::ClipShader; + ClipShader(const sk_sp<SkShader>& shader, SkClipOp op) : shader(shader), op(op) {} + sk_sp<SkShader> shader; + SkClipOp op; + void draw(SkCanvas* c, const SkMatrix&) const { c->clipShader(shader, op); } +}; struct ResetClip final : Op { static const auto kType = Type::ResetClip; ResetClip() {} @@ -822,6 +829,9 @@ void DisplayListData::clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) { void DisplayListData::clipRegion(const SkRegion& region, SkClipOp op) { this->push<ClipRegion>(0, region, op); } +void DisplayListData::clipShader(const sk_sp<SkShader>& shader, SkClipOp op) { + this->push<ClipShader>(0, shader, op); +} void DisplayListData::resetClip() { this->push<ResetClip>(0); } @@ -1134,6 +1144,11 @@ void RecordingCanvas::onClipRegion(const SkRegion& region, SkClipOp op) { fDL->clipRegion(region, op); this->INHERITED::onClipRegion(region, op); } +void RecordingCanvas::onClipShader(sk_sp<SkShader> shader, SkClipOp op) { + setClipMayBeComplex(); + fDL->clipShader(shader, op); + this->INHERITED::onClipShader(shader, op); +} void RecordingCanvas::onResetClip() { // This is part of "replace op" emulation, but rely on the following intersection // clip to potentially mark the clip as complex. If we are already complex, we do diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index afadbfda7471..965264f31119 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -140,6 +140,7 @@ private: void translateZ(SkScalar); void clipPath(const SkPath&, SkClipOp, bool aa); + void clipShader(const sk_sp<SkShader>& shader, SkClipOp); void clipRect(const SkRect&, SkClipOp, bool aa); void clipRRect(const SkRRect&, SkClipOp, bool aa); void clipRegion(const SkRegion&, SkClipOp); @@ -216,6 +217,7 @@ public: void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipShader(sk_sp<SkShader>, SkClipOp) override; void onClipRegion(const SkRegion&, SkClipOp) override; void onResetClip() override; diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index f84107e8792c..f9dc5fac7e21 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -41,6 +41,8 @@ namespace android { namespace { +static const bool ENABLE_POINTER_CHOREOGRAPHER = input_flags::enable_pointer_choreographer(); + const ui::Transform kIdentityTransform; } // namespace @@ -224,7 +226,7 @@ void PointerController::setPresentation(Presentation presentation) { mLocked.presentation = presentation; - if (input_flags::enable_pointer_choreographer()) { + if (ENABLE_POINTER_CHOREOGRAPHER) { // When pointer choreographer is enabled, the presentation mode is only set once when the // PointerController is constructed, before the display viewport is provided. // TODO(b/293587049): Clean up the PointerController interface after pointer choreographer diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index ea136edf46be..c90c44152440 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -1079,7 +1079,7 @@ public final class AudioFormat implements Parcelable { * @return one of the values that can be set in {@link Builder#setEncoding(int)} or * {@link AudioFormat#ENCODING_INVALID} if not set. */ - public @Encoding int getEncoding() { + public @EncodingCanBeInvalid int getEncoding() { return mEncoding; } @@ -1486,6 +1486,44 @@ public final class AudioFormat implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface Encoding {} + /** @hide same as @Encoding, but adding ENCODING_INVALID */ + @IntDef(flag = false, prefix = "ENCODING", value = { + ENCODING_INVALID, + ENCODING_DEFAULT, + ENCODING_PCM_16BIT, + ENCODING_PCM_8BIT, + ENCODING_PCM_FLOAT, + ENCODING_AC3, + ENCODING_E_AC3, + ENCODING_DTS, + ENCODING_DTS_HD, + ENCODING_MP3, + ENCODING_AAC_LC, + ENCODING_AAC_HE_V1, + ENCODING_AAC_HE_V2, + ENCODING_IEC61937, + ENCODING_DOLBY_TRUEHD, + ENCODING_AAC_ELD, + ENCODING_AAC_XHE, + ENCODING_AC4, + ENCODING_E_AC3_JOC, + ENCODING_DOLBY_MAT, + ENCODING_OPUS, + ENCODING_PCM_24BIT_PACKED, + ENCODING_PCM_32BIT, + ENCODING_MPEGH_BL_L3, + ENCODING_MPEGH_BL_L4, + ENCODING_MPEGH_LC_L3, + ENCODING_MPEGH_LC_L4, + ENCODING_DTS_UHD_P1, + ENCODING_DRA, + ENCODING_DTS_HD_MA, + ENCODING_DTS_UHD_P2, + ENCODING_DSD } + ) + @Retention(RetentionPolicy.SOURCE) + public @interface EncodingCanBeInvalid {} + /** @hide */ public static final int[] SURROUND_SOUND_ENCODING = { ENCODING_AC3, diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java index 48b476651c91..60ab1a4e42ac 100644 --- a/media/java/android/media/audiopolicy/AudioMix.java +++ b/media/java/android/media/audiopolicy/AudioMix.java @@ -27,7 +27,9 @@ import android.compat.annotation.UnsupportedAppUsage; import android.media.AudioDeviceInfo; import android.media.AudioFormat; import android.media.AudioSystem; +import android.os.Binder; import android.os.Build; +import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; @@ -52,6 +54,8 @@ public class AudioMix implements Parcelable { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int mMixType = MIX_TYPE_INVALID; + private final IBinder mToken; + // written by AudioPolicy int mMixState = MIX_STATE_DISABLED; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -68,7 +72,7 @@ public class AudioMix implements Parcelable { */ private AudioMix(@NonNull AudioMixingRule rule, @NonNull AudioFormat format, int routeFlags, int callbackFlags, - int deviceType, @Nullable String deviceAddress) { + int deviceType, @Nullable String deviceAddress, IBinder token) { mRule = Objects.requireNonNull(rule); mFormat = Objects.requireNonNull(format); mRouteFlags = routeFlags; @@ -76,6 +80,7 @@ public class AudioMix implements Parcelable { mCallbackFlags = callbackFlags; mDeviceSystemType = deviceType; mDeviceAddress = (deviceAddress == null) ? new String("") : deviceAddress; + mToken = token; } // CALLBACK_FLAG_* values: keep in sync with AudioMix::kCbFlag* values defined @@ -273,13 +278,14 @@ public class AudioMix implements Parcelable { return Objects.equals(this.mRouteFlags, that.mRouteFlags) && Objects.equals(this.mRule, that.mRule) && Objects.equals(this.mMixType, that.mMixType) - && Objects.equals(this.mFormat, that.mFormat); + && Objects.equals(this.mFormat, that.mFormat) + && Objects.equals(this.mToken, that.mToken); } /** @hide */ @Override public int hashCode() { - return Objects.hash(mRouteFlags, mRule, mMixType, mFormat); + return Objects.hash(mRouteFlags, mRule, mMixType, mFormat, mToken); } @Override @@ -298,6 +304,7 @@ public class AudioMix implements Parcelable { dest.writeString8(mDeviceAddress); mFormat.writeToParcel(dest, flags); mRule.writeToParcel(dest, flags); + dest.writeStrongBinder(mToken); } public static final @NonNull Parcelable.Creator<AudioMix> CREATOR = new Parcelable.Creator<>() { @@ -317,6 +324,7 @@ public class AudioMix implements Parcelable { mixBuilder.setDevice(p.readInt(), p.readString8()); mixBuilder.setFormat(AudioFormat.CREATOR.createFromParcel(p)); mixBuilder.setMixingRule(AudioMixingRule.CREATOR.createFromParcel(p)); + mixBuilder.setToken(p.readStrongBinder()); return mixBuilder.build(); } @@ -339,6 +347,7 @@ public class AudioMix implements Parcelable { private AudioFormat mFormat = null; private int mRouteFlags = 0; private int mCallbackFlags = 0; + private IBinder mToken = null; // an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_* private int mDeviceSystemType = AudioSystem.DEVICE_NONE; private String mDeviceAddress = null; @@ -380,6 +389,15 @@ public class AudioMix implements Parcelable { /** * @hide + * Only used by AudioMix internally. + */ + Builder setToken(IBinder token) { + mToken = token; + return this; + } + + /** + * @hide * Only used by AudioPolicyConfig, not a public API. * @param callbackFlags which callbacks are called from native * @return the same Builder instance. @@ -540,8 +558,13 @@ public class AudioMix implements Parcelable { throw new IllegalArgumentException(error); } } + + if (mToken == null) { + mToken = new Binder(); + } + return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags, mDeviceSystemType, - mDeviceAddress); + mDeviceAddress, mToken); } private int getLoopbackDeviceSystemTypeForAudioMixingRule(AudioMixingRule rule) { diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index bbe461c95ed9..508c0a2b9a21 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -337,7 +337,9 @@ public class AudioPolicy { /** * Update the current configuration of the set of audio mixes by adding new ones, while - * keeping the policy registered. + * keeping the policy registered. If any of the provided audio mixes is invalid then none of + * the passed mixes will be registered. + * * This method can only be called on a registered policy. * @param mixes the list of {@link AudioMix} to add * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR} @@ -375,12 +377,15 @@ public class AudioPolicy { } /** - * Update the current configuration of the set of audio mixes by removing some, while - * keeping the policy registered. - * This method can only be called on a registered policy. + * Update the current configuration of the set of audio mixes for this audio policy by + * removing some, while keeping the policy registered. Will unregister all provided audio + * mixes, if possible. + * + * This method can only be called on a registered policy and only affects this current policy. * @param mixes the list of {@link AudioMix} to remove * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR} - * otherwise. + * otherwise. If only some of the provided audio mixes were detached but any one mix + * failed to be detached, this method returns {@link AudioManager#ERROR}. */ public int detachMixes(@NonNull List<AudioMix> mixes) { if (mixes == null) { @@ -394,7 +399,6 @@ public class AudioPolicy { for (AudioMix mix : mixes) { if (mix == null) { throw new IllegalArgumentException("Illegal null AudioMix in detachMixes"); - // TODO also check mix is currently contained in list of mixes } else { zeMixes.add(mix); } diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java index d277c7dfbea4..5e7c7c453df3 100644 --- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java +++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java @@ -228,7 +228,7 @@ public class AudioPolicyConfig implements Parcelable { } } - private void setMixRegistration(@NonNull final AudioMix mix) { + protected void setMixRegistration(@NonNull final AudioMix mix) { if (!mRegistrationId.isEmpty()) { if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) == AudioMix.ROUTE_FLAG_LOOP_BACK) { @@ -246,7 +246,9 @@ public class AudioPolicyConfig implements Parcelable { @GuardedBy("mMixes") protected void add(@NonNull ArrayList<AudioMix> mixes) { for (AudioMix mix : mixes) { - setMixRegistration(mix); + if (mix.getRegistration() == null || mix.getRegistration().isEmpty()) { + setMixRegistration(mix); + } mMixes.add(mix); } } diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java index d1453975f801..ed543e67fdf1 100644 --- a/media/java/android/media/tv/ITvInputSessionWrapper.java +++ b/media/java/android/media/tv/ITvInputSessionWrapper.java @@ -519,7 +519,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand @Override public void stopPlayback(int mode) { - mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_STOP_PLAYBACK, mode)); + mCaller.executeOrSendMessage(mCaller.obtainMessageI(DO_STOP_PLAYBACK, mode)); } @Override diff --git a/nfc/api/current.txt b/nfc/api/current.txt index 7b53ca6ea7e9..9d0221a3ae68 100644 --- a/nfc/api/current.txt +++ b/nfc/api/current.txt @@ -204,11 +204,11 @@ package android.nfc.cardemulation { method public boolean isDefaultServiceForAid(android.content.ComponentName, String); method public boolean isDefaultServiceForCategory(android.content.ComponentName, String); method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>); - method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String); + method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean); method public boolean removeAidsForService(android.content.ComponentName, String); - method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setDefaultToObserveModeForService(@NonNull android.content.ComponentName, boolean); method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String); method public boolean setPreferredService(android.app.Activity, android.content.ComponentName); + method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setShouldDefaultToObserveModeForService(@NonNull android.content.ComponentName, boolean); method public boolean supportsAidPrefixRegistration(); method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean unsetOffHostForService(@NonNull android.content.ComponentName); method public boolean unsetPreferredService(android.app.Activity); diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl index 65d0625f251e..85a07b74871b 100644 --- a/nfc/java/android/nfc/INfcCardEmulation.aidl +++ b/nfc/java/android/nfc/INfcCardEmulation.aidl @@ -30,9 +30,9 @@ interface INfcCardEmulation boolean isDefaultServiceForAid(int userHandle, in ComponentName service, String aid); boolean setDefaultServiceForCategory(int userHandle, in ComponentName service, String category); boolean setDefaultForNextTap(int userHandle, in ComponentName service); - boolean setDefaultToObserveModeForService(int userId, in android.content.ComponentName service, boolean enable); + boolean setShouldDefaultToObserveModeForService(int userId, in android.content.ComponentName service, boolean enable); boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup); - boolean registerPollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter); + boolean registerPollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter, boolean autoTransact); boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement); boolean unsetOffHostForService(int userHandle, in ComponentName service); AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category); diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java index c81b95b7c81b..2c7d61eea777 100644 --- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -141,7 +141,7 @@ public final class ApduServiceInfo implements Parcelable { /** * Whether the NFC stack should default to Observe Mode when this preferred service. */ - private boolean mDefaultToObserveMode; + private boolean mShouldDefaultToObserveMode; /** * @hide @@ -275,8 +275,8 @@ public final class ApduServiceInfo implements Parcelable { com.android.internal.R.styleable.HostApduService_settingsActivity); mOffHostName = null; mStaticOffHostName = mOffHostName; - mDefaultToObserveMode = sa.getBoolean( - R.styleable.HostApduService_defaultToObserveMode, + mShouldDefaultToObserveMode = sa.getBoolean( + R.styleable.HostApduService_shouldDefaultToObserveMode, false); sa.recycle(); } else { @@ -297,8 +297,8 @@ public final class ApduServiceInfo implements Parcelable { com.android.internal.R.styleable.HostApduService_settingsActivity); mOffHostName = sa.getString( com.android.internal.R.styleable.OffHostApduService_secureElementName); - mDefaultToObserveMode = sa.getBoolean( - R.styleable.HostApduService_defaultToObserveMode, + mShouldDefaultToObserveMode = sa.getBoolean( + R.styleable.HostApduService_shouldDefaultToObserveMode, false); if (mOffHostName != null) { if (mOffHostName.equals("eSE")) { @@ -633,22 +633,22 @@ public final class ApduServiceInfo implements Parcelable { } /** - * Returns whether the NFC stack should default to observe mode when this servise is preferred. - * @return whether the NFC stack should default to observe mode when this servise is preferred + * Returns whether the NFC stack should default to observe mode when this service is preferred. + * @return whether the NFC stack should default to observe mode when this service is preferred */ @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE) - public boolean defaultToObserveMode() { - return mDefaultToObserveMode; + public boolean shouldDefaultToObserveMode() { + return mShouldDefaultToObserveMode; } /** - * Sets whether the NFC stack should default to observe mode when this servise is preferred. - * @param defaultToObserveMode whether the NFC stack should default to observe mode when this - * servise is preferred + * Sets whether the NFC stack should default to observe mode when this service is preferred. + * @param shouldDefaultToObserveMode whether the NFC stack should default to observe mode when + * this service is preferred */ @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE) - public void setDefaultToObserveMode(boolean defaultToObserveMode) { - mDefaultToObserveMode = defaultToObserveMode; + public void setShouldDefaultToObserveMode(boolean shouldDefaultToObserveMode) { + mShouldDefaultToObserveMode = shouldDefaultToObserveMode; } /** @@ -681,34 +681,18 @@ public final class ApduServiceInfo implements Parcelable { /** * Add a Polling Loop Filter. Custom NFC polling frames that match this filter will be - * delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this or - * {@link ApduServiceInfo#addPollingLoopFilterToAutoTransact(String)} multiple times will - * cause the value to be overwritten each time. + * delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this + * multiple times will cause the value to be overwritten each time. * @param pollingLoopFilter the polling loop filter to add, must be a valide hexadecimal string */ @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) - public void addPollingLoopFilter(@NonNull String pollingLoopFilter) { - mAutoTransact.put(pollingLoopFilter.toUpperCase(Locale.ROOT), false); + public void addPollingLoopFilter(@NonNull String pollingLoopFilter, + boolean autoTransact) { + mAutoTransact.put(pollingLoopFilter, autoTransact); } /** - * Add a Polling Loop Filter. Custom NFC polling frames that match this filter will cause the - * device to exit observe mode, just as if - * {@link android.nfc.NfcAdapter#setObserveModeEnabled(boolean)} had been called with true, - * allowing transactions to proceed. The matching frame will also be delivered to - * {@link HostApduService#processPollingFrames(List)}. Adding a key with this or - * {@link ApduServiceInfo#addPollingLoopFilter(String)} multiple times will - * cause the value to be overwritten each time. - * - * @param pollingLoopFilter the polling loop filter to add, must be a valide hexadecimal string - */ - @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) - public void addPollingLoopFilterToAutoTransact(@NonNull String pollingLoopFilter) { - mAutoTransact.put(pollingLoopFilter.toUpperCase(Locale.ROOT), true); - } - - /** * Remove a Polling Loop Filter. Custom NFC polling frames that match this filter will no * longer be delivered to {@link HostApduService#processPollingFrames(List)}. * @param pollingLoopFilter this polling loop filter to add. diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java index e681a8568300..ea58504063d7 100644 --- a/nfc/java/android/nfc/cardemulation/CardEmulation.java +++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java @@ -42,6 +42,7 @@ import android.provider.Settings.SettingNotFoundException; import android.util.Log; import java.util.HashMap; +import java.util.HexFormat; import java.util.List; import java.util.regex.Pattern; @@ -59,7 +60,6 @@ import java.util.regex.Pattern; */ public final class CardEmulation { private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?"); - private static final Pattern PLF_PATTERN = Pattern.compile("[0-9A-Fa-f]{1,32}"); static final String TAG = "CardEmulation"; @@ -348,11 +348,11 @@ public final class CardEmulation { * @return whether the change was successful. */ @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE) - public boolean setDefaultToObserveModeForService(@NonNull ComponentName service, + public boolean setShouldDefaultToObserveModeForService(@NonNull ComponentName service, boolean enable) { try { - return sService.setDefaultToObserveModeForService(mContext.getUser().getIdentifier(), - service, enable); + return sService.setShouldDefaultToObserveModeForService( + mContext.getUser().getIdentifier(), service, enable); } catch (RemoteException e) { Log.e(TAG, "Failed to reach CardEmulationService."); } @@ -360,21 +360,28 @@ public final class CardEmulation { } /** - * Register a polling loop filter (PLF) for a HostApduService. The PLF can be sequence of an - * even number of hexadecimal numbers (0-9, A-F or a-f). When non-standard polling loop frame - * matches this sequence exactly, it may be delivered to - * {@link HostApduService#processPollingFrames(List)} if this service is currently - * preferred or there are no other services registered for this filter. + * Register a polling loop filter (PLF) for a HostApduService and indicate whether it should + * auto-transact or not. The PLF can be sequence of an + * even number of at least 2 hexadecimal numbers (0-9, A-F or a-f), representing a series of + * bytes. When non-standard polling loop frame matches this sequence exactly, it may be + * delivered to {@link HostApduService#processPollingFrames(List)}. If auto-transact is set to + * true, then observe mode will also be disabled. if this service is currently preferred or + * there are no other services registered for this filter. * @param service The HostApduService to register the filter for * @param pollingLoopFilter The filter to register + * @param autoTransact true to have the NFC stack automatically disable observe mode and allow + * transactions to proceed when this filter matches, false otherwise * @return true if the filter was registered, false otherwise + * @throws IllegalArgumentException if the passed in string doesn't parse to at least one byte */ @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) public boolean registerPollingLoopFilterForService(@NonNull ComponentName service, - @NonNull String pollingLoopFilter) { + @NonNull String pollingLoopFilter, boolean autoTransact) { + pollingLoopFilter = validatePollingLoopFilter(pollingLoopFilter); + try { return sService.registerPollingLoopFilterForService(mContext.getUser().getIdentifier(), - service, pollingLoopFilter); + service, pollingLoopFilter, autoTransact); } catch (RemoteException e) { // Try one more time recoverService(); @@ -384,7 +391,8 @@ public final class CardEmulation { } try { return sService.registerPollingLoopFilterForService( - mContext.getUser().getIdentifier(), service, pollingLoopFilter); + mContext.getUser().getIdentifier(), service, + pollingLoopFilter, autoTransact); } catch (RemoteException ee) { Log.e(TAG, "Failed to reach CardEmulationService."); return false; @@ -979,15 +987,14 @@ public final class CardEmulation { * @hide */ @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP) - public static boolean isValidPollingLoopFilter(@NonNull String pollingLoopFilter) { + public static @NonNull String validatePollingLoopFilter(@NonNull String pollingLoopFilter) { // Verify hex characters - if (!PLF_PATTERN.matcher(pollingLoopFilter).matches()) { - Log.e(TAG, "Polling Loop Filter " + pollingLoopFilter - + " is not a valid Polling Loop Filter."); - return false; + byte[] plfBytes = HexFormat.of().parseHex(pollingLoopFilter); + if (plfBytes.length == 0) { + throw new IllegalArgumentException( + "Polling loop filter must contain at least one byte."); } - - return true; + return HexFormat.of().withUpperCase().formatHex(plfBytes); } /** diff --git a/packages/CrashRecovery/framework/Android.bp b/packages/CrashRecovery/framework/Android.bp index c0d93531a1e6..9480327253f4 100644 --- a/packages/CrashRecovery/framework/Android.bp +++ b/packages/CrashRecovery/framework/Android.bp @@ -3,7 +3,7 @@ soong_config_module_type { module_type: "filegroup", config_namespace: "ANDROID", bool_variables: [ - "move_crashrecovery_files", + "crashrecovery_files_in_platform", ], properties: [ "srcs", @@ -12,14 +12,13 @@ soong_config_module_type { platform_filegroup { name: "framework-crashrecovery-sources", - srcs: [ - "java/**/*.java", - "java/**/*.aidl", - ], soong_config_variables: { - // if the flag is enabled, then files would be moved to module - move_crashrecovery_files: { - srcs: [], + // if this flag is enabled, then files are part of platform + crashrecovery_files_in_platform: { + srcs: [ + "java/**/*.java", + "java/**/*.aidl", + ], }, }, path: "java", @@ -31,7 +30,7 @@ soong_config_module_type { module_type: "filegroup", config_namespace: "ANDROID", bool_variables: [ - "move_crashrecovery_files", + "crashrecovery_files_in_module", ], properties: [ "srcs", @@ -40,10 +39,9 @@ soong_config_module_type { module_filegroup { name: "framework-crashrecovery-module-sources", - srcs: [], soong_config_variables: { - // if the flag is enabled, then files would be moved to module - move_crashrecovery_files: { + // if this flag is enabled, then files are part of module + crashrecovery_files_in_module: { srcs: [ "java/**/*.java", "java/**/*.aidl", diff --git a/packages/CrashRecovery/services/Android.bp b/packages/CrashRecovery/services/Android.bp index ab10b5a23676..961b41f4a633 100644 --- a/packages/CrashRecovery/services/Android.bp +++ b/packages/CrashRecovery/services/Android.bp @@ -3,7 +3,7 @@ soong_config_module_type { module_type: "filegroup", config_namespace: "ANDROID", bool_variables: [ - "move_crashrecovery_files", + "crashrecovery_files_in_platform", ], properties: [ "srcs", @@ -12,15 +12,14 @@ soong_config_module_type { platform_filegroup { name: "services-crashrecovery-sources", - srcs: [ - "java/**/*.java", - "java/**/*.aidl", - ":statslog-crashrecovery-java-gen", - ], soong_config_variables: { - // if the flag is enabled, then files would be moved to module - move_crashrecovery_files: { - srcs: [], + // if this flag is enabled, then files are part of platform + crashrecovery_files_in_platform: { + srcs: [ + "java/**/*.java", + "java/**/*.aidl", + ":statslog-crashrecovery-java-gen", + ], }, }, visibility: ["//frameworks/base:__subpackages__"], @@ -31,7 +30,7 @@ soong_config_module_type { module_type: "filegroup", config_namespace: "ANDROID", bool_variables: [ - "move_crashrecovery_files", + "crashrecovery_files_in_module", ], properties: [ "srcs", @@ -40,10 +39,9 @@ soong_config_module_type { module_filegroup { name: "services-crashrecovery-module-sources", - srcs: [], soong_config_variables: { - // if the flag is enabled, then files would be moved to module - move_crashrecovery_files: { + // if this flag is enabled, then files are part of module + crashrecovery_files_in_module: { srcs: [ "java/**/*.java", "java/**/*.aidl", diff --git a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java index ce8fb6568bd5..5d71b7d98fdc 100644 --- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java +++ b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java @@ -38,13 +38,13 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; +import android.util.BackgroundThread; import android.util.LongArrayQueue; import android.util.Slog; import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; diff --git a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java index 5fb47dd9b95a..0fb932735ab4 100644 --- a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -75,6 +75,9 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver { private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT | ApplicationInfo.FLAG_SYSTEM; + private static final String PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG = + "persist.device_config.configuration.disable_high_impact_rollback"; + private final Context mContext; private final Handler mHandler; private final ApexManager mApexManager; @@ -605,6 +608,10 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver { // Apply all available low impact rollbacks. mHandler.post(() -> rollbackAllLowImpact(availableRollbacks, rollbackReason)); } else if (minRollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_HIGH) { + // Check disable_high_impact_rollback device config before performing rollback + if (SystemProperties.getBoolean(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, false)) { + return; + } // Rollback one package at a time. If that doesn't resolve the issue, rollback // next with same impact level. mHandler.post(() -> rollbackHighImpact(availableRollbacks, rollbackReason)); @@ -718,7 +725,9 @@ final class RollbackPackageHealthObserver implements PackageHealthObserver { impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70; break; case PackageManager.ROLLBACK_USER_IMPACT_HIGH: - impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_90; + if (!SystemProperties.getBoolean(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, false)) { + impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_90; + } break; default: impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0; diff --git a/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java b/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java new file mode 100644 index 000000000000..a6ae68f62f10 --- /dev/null +++ b/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java @@ -0,0 +1,103 @@ +/* + * * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +import android.annotation.NonNull; +import android.os.Handler; +import android.os.HandlerThread; + +import com.android.internal.annotations.GuardedBy; + +import java.util.concurrent.Executor; + +/** + * Thread for asynchronous event processing. This thread is configured as + * {@link android.os.Process#THREAD_PRIORITY_BACKGROUND}, which means fewer CPU + * resources will be dedicated to it, and it will "have less chance of impacting + * the responsiveness of the user interface." + * <p> + * This thread is best suited for tasks that the user is not actively waiting + * for, or for tasks that the user expects to be executed eventually. + * + * @see com.android.internal.os.BackgroundThread + * + * TODO: b/326916057 depend on modules-utils-backgroundthread instead + * @hide + */ +public final class BackgroundThread extends HandlerThread { + private static final Object sLock = new Object(); + + @GuardedBy("sLock") + private static BackgroundThread sInstance; + @GuardedBy("sLock") + private static Handler sHandler; + @GuardedBy("sLock") + private static HandlerExecutor sHandlerExecutor; + + private BackgroundThread() { + super(BackgroundThread.class.getName(), android.os.Process.THREAD_PRIORITY_BACKGROUND); + } + + @GuardedBy("sLock") + private static void ensureThreadLocked() { + if (sInstance == null) { + sInstance = new BackgroundThread(); + sInstance.start(); + sHandler = new Handler(sInstance.getLooper()); + sHandlerExecutor = new HandlerExecutor(sHandler); + } + } + + /** + * Get the singleton instance of this class. + * + * @return the singleton instance of this class + */ + @NonNull + public static BackgroundThread get() { + synchronized (sLock) { + ensureThreadLocked(); + return sInstance; + } + } + + /** + * Get the singleton {@link Handler} for this class. + * + * @return the singleton {@link Handler} for this class. + */ + @NonNull + public static Handler getHandler() { + synchronized (sLock) { + ensureThreadLocked(); + return sHandler; + } + } + + /** + * Get the singleton {@link Executor} for this class. + * + * @return the singleton {@link Executor} for this class. + */ + @NonNull + public static Executor getExecutor() { + synchronized (sLock) { + ensureThreadLocked(); + return sHandlerExecutor; + } + } +} diff --git a/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java b/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java new file mode 100644 index 000000000000..948ebcca0263 --- /dev/null +++ b/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +import android.annotation.NonNull; +import android.os.Handler; + +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; + +/** + * An adapter {@link Executor} that posts all executed tasks onto the given + * {@link Handler}. + * + * TODO: b/326916057 depend on modules-utils-backgroundthread instead + * @hide + */ +public class HandlerExecutor implements Executor { + private final Handler mHandler; + + public HandlerExecutor(@NonNull Handler handler) { + mHandler = Objects.requireNonNull(handler); + } + + @Override + public void execute(Runnable command) { + if (!mHandler.post(command)) { + throw new RejectedExecutionException(mHandler + " is shutting down"); + } + } +} diff --git a/packages/CredentialManager/res/drawable/ic_passkey_24.xml b/packages/CredentialManager/res/drawable/ic_passkey_24.xml index a2c4f374caf1..5298f9eda88e 100644 --- a/packages/CredentialManager/res/drawable/ic_passkey_24.xml +++ b/packages/CredentialManager/res/drawable/ic_passkey_24.xml @@ -13,16 +13,14 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - -<vector - android:alpha="0.8" - android:height="24dp" - android:viewportHeight="24" - android:viewportWidth="24" - android:width="24dp" - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools"> - <path android:fillColor="#4C463C" android:fillType="evenOdd" android:pathData="M22.18,14.09C22.18,15.364 21.408,16.459 20.306,16.931L21.247,17.872L20.219,18.9L21.247,19.928L19.068,22.107L18.099,21.138L18.099,17.017C16.878,16.604 16,15.45 16,14.09C16,12.383 17.383,11 19.09,11C20.796,11 22.18,12.383 22.18,14.09ZM20.692,14.091C20.692,14.976 19.975,15.693 19.09,15.693C18.205,15.693 17.488,14.976 17.488,14.091C17.488,13.206 18.205,12.488 19.09,12.488C19.975,12.488 20.692,13.206 20.692,14.091Z"/> - <path android:fillColor="#4C463C" android:pathData="M14.978,8.476C14.978,10.865 13.041,12.802 10.652,12.802C8.263,12.802 6.326,10.865 6.326,8.476C6.326,6.087 8.263,4.15 10.652,4.15C13.041,4.15 14.978,6.087 14.978,8.476Z"/> - <path android:fillColor="#4C463C" android:pathData="M2,19.263C2,16.39 7.762,14.937 10.652,14.937C11.782,14.937 13.353,15.16 14.845,15.602C15.177,16.491 15.804,17.236 16.607,17.717V21.454H2V19.263Z"/> +<!--LINT.IfChange--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960"> + <path + android:fillColor="@android:color/white" + android:pathData="M120,800L120,688Q120,654 137.5,625.5Q155,597 184,582Q246,551 310,535.5Q374,520 440,520Q460,520 480,521.5Q500,523 520,526Q516,584 541,635.5Q566,687 614,720L614,800L120,800ZM760,920L700,860L700,674Q656,661 628,624.5Q600,588 600,540Q600,482 641,441Q682,400 740,400Q798,400 839,441Q880,482 880,540Q880,585 854.5,620Q829,655 790,670L840,720L780,780L840,840L760,920ZM440,480Q374,480 327,433Q280,386 280,320Q280,254 327,207Q374,160 440,160Q506,160 553,207Q600,254 600,320Q600,386 553,433Q506,480 440,480ZM740,560Q757,560 768.5,548.5Q780,537 780,520Q780,503 768.5,491.5Q757,480 740,480Q723,480 711.5,491.5Q700,503 700,520Q700,537 711.5,548.5Q723,560 740,560Z"/> </vector> +<!--LINT.ThenChange(/packages/CredentialManager/shared/res/drawable/ic_passkey_24.xml)-->
\ No newline at end of file diff --git a/packages/CredentialManager/shared/Android.bp b/packages/CredentialManager/shared/Android.bp index 47ca944c479c..f8ee96ebe7e4 100644 --- a/packages/CredentialManager/shared/Android.bp +++ b/packages/CredentialManager/shared/Android.bp @@ -11,6 +11,7 @@ android_library { name: "CredentialManagerShared", manifest: "AndroidManifest.xml", srcs: ["src/**/*.kt"], + resource_dirs: ["res"], static_libs: [ "androidx.activity_activity-compose", "androidx.core_core-ktx", diff --git a/packages/CredentialManager/shared/res/drawable/ic_passkey_24.xml b/packages/CredentialManager/shared/res/drawable/ic_passkey_24.xml new file mode 100644 index 000000000000..b81f7c500753 --- /dev/null +++ b/packages/CredentialManager/shared/res/drawable/ic_passkey_24.xml @@ -0,0 +1,26 @@ +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<!--LINT.IfChange--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="960" + android:viewportHeight="960"> + <path + android:fillColor="@android:color/white" + android:pathData="M120,800L120,688Q120,654 137.5,625.5Q155,597 184,582Q246,551 310,535.5Q374,520 440,520Q460,520 480,521.5Q500,523 520,526Q516,584 541,635.5Q566,687 614,720L614,800L120,800ZM760,920L700,860L700,674Q656,661 628,624.5Q600,588 600,540Q600,482 641,441Q682,400 740,400Q798,400 839,441Q880,482 880,540Q880,585 854.5,620Q829,655 790,670L840,720L780,780L840,840L760,920ZM440,480Q374,480 327,433Q280,386 280,320Q280,254 327,207Q374,160 440,160Q506,160 553,207Q600,254 600,320Q600,386 553,433Q506,480 440,480ZM740,560Q757,560 768.5,548.5Q780,537 780,520Q780,503 768.5,491.5Q757,480 740,480Q723,480 711.5,491.5Q700,503 700,520Q700,537 711.5,548.5Q723,560 740,560Z"/> +</vector> +<!--LINT.ThenChange(/packages/CredentialManager/res/drawable/ic_passkey_24.xml)-->
\ No newline at end of file diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt index a5f227a3adc9..39d3f42e8bf4 100644 --- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt +++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt @@ -39,6 +39,7 @@ import androidx.credentials.provider.PasswordCredentialEntry import androidx.credentials.provider.PublicKeyCredentialEntry import androidx.credentials.provider.RemoteEntry import com.android.credentialmanager.IS_AUTO_SELECTED_KEY +import com.android.credentialmanager.R import com.android.credentialmanager.model.get.ActionEntryInfo import com.android.credentialmanager.model.get.AuthenticationEntryInfo import com.android.credentialmanager.model.get.CredentialEntryInfo @@ -127,10 +128,10 @@ private fun getCredentialOptionInfoList( userName = credentialEntry.username.toString(), displayName = credentialEntry.displayName?.toString(), icon = credentialEntry.icon.loadDrawable(context), - shouldTintIcon = credentialEntry.isDefaultIcon, + shouldTintIcon = credentialEntry.hasDefaultIcon, lastUsedTimeMillis = credentialEntry.lastUsedTime, isAutoSelectable = credentialEntry.isAutoSelectAllowed && - credentialEntry.autoSelectAllowedFromOption, + credentialEntry.isAutoSelectAllowedFromOption, ) ) } @@ -147,11 +148,13 @@ private fun getCredentialOptionInfoList( credentialTypeDisplayName = credentialEntry.typeDisplayName.toString(), userName = credentialEntry.username.toString(), displayName = credentialEntry.displayName?.toString(), - icon = credentialEntry.icon.loadDrawable(context), - shouldTintIcon = credentialEntry.isDefaultIcon, + icon = if (credentialEntry.hasDefaultIcon) + context.getDrawable(R.drawable.ic_passkey_24) + else credentialEntry.icon.loadDrawable(context), + shouldTintIcon = credentialEntry.hasDefaultIcon, lastUsedTimeMillis = credentialEntry.lastUsedTime, isAutoSelectable = credentialEntry.isAutoSelectAllowed && - credentialEntry.autoSelectAllowedFromOption, + credentialEntry.isAutoSelectAllowedFromOption, ) ) } @@ -170,10 +173,10 @@ private fun getCredentialOptionInfoList( userName = credentialEntry.title.toString(), displayName = credentialEntry.subtitle?.toString(), icon = credentialEntry.icon.loadDrawable(context), - shouldTintIcon = credentialEntry.isDefaultIcon, + shouldTintIcon = credentialEntry.hasDefaultIcon, lastUsedTimeMillis = credentialEntry.lastUsedTime, isAutoSelectable = credentialEntry.isAutoSelectAllowed && - credentialEntry.autoSelectAllowedFromOption, + credentialEntry.isAutoSelectAllowedFromOption, ) ) } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt index 5830b9fc1028..ccf401da5a4c 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt @@ -282,6 +282,8 @@ class CreateFlowUtils { val appPreferredDefaultProviderId: String? = if (!requestInfo.hasPermissionToOverrideDefault()) null else createCredentialRequestJetpack?.displayInfo?.preferDefaultProvider + val typeDisplayIcon = createCredentialRequestJetpack?.displayInfo?.credentialTypeIcon + ?.loadDrawable(context) return when (createCredentialRequestJetpack) { is CreatePasswordRequest -> RequestDisplayInfo( createCredentialRequestJetpack.id, @@ -302,7 +304,6 @@ class CreateFlowUtils { newRequestDisplayInfoFromPasskeyJson( requestJson = createCredentialRequestJetpack.requestJson, appLabel = appLabel, - context = context, preferImmediatelyAvailableCredentials = createCredentialRequestJetpack.preferImmediatelyAvailableCredentials, appPreferredDefaultProviderId = appPreferredDefaultProviderId, @@ -311,6 +312,7 @@ class CreateFlowUtils { // the passkey type. For now, directly parse it ourselves. isAutoSelectRequest = createCredentialRequest.credentialData.getBoolean( Constants.BUNDLE_KEY_PREFER_IMMEDIATELY_AVAILABLE_CREDENTIALS, false), + typeIcon = context.getDrawable(R.drawable.ic_passkey_24) ?: return null, ) } is CreateCustomCredentialRequest -> { @@ -323,7 +325,7 @@ class CreateFlowUtils { subtitle = displayInfo.userDisplayName?.toString(), type = CredentialType.UNKNOWN, appName = appLabel, - typeIcon = displayInfo.credentialTypeIcon?.loadDrawable(context) + typeIcon = typeDisplayIcon ?: context.getDrawable(R.drawable.ic_other_sign_in_24) ?: return null, preferImmediatelyAvailableCredentials = createCredentialRequestJetpack.preferImmediatelyAvailableCredentials, @@ -502,7 +504,7 @@ class CreateFlowUtils { private fun newRequestDisplayInfoFromPasskeyJson( requestJson: String, appLabel: String, - context: Context, + typeIcon: Drawable, preferImmediatelyAvailableCredentials: Boolean, appPreferredDefaultProviderId: String?, userSetDefaultProviderIds: Set<String>, @@ -525,7 +527,7 @@ class CreateFlowUtils { displayname, CredentialType.PASSKEY, appLabel, - context.getDrawable(R.drawable.ic_passkey_24) ?: return null, + typeIcon, preferImmediatelyAvailableCredentials, appPreferredDefaultProviderId, userSetDefaultProviderIds, diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt index 0f1721790295..13260231038d 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt @@ -213,7 +213,7 @@ class CredentialAutofillService : AutofillService() { autofillIdToProvidersMap.forEach { (autofillId, providers) -> validFillResponse = processProvidersForAutofillId( filLRequest, autofillId, providers, entryIconMap, fillResponseBuilder, - getCredResponse.pendingIntent) + getCredResponse.intent) .or(validFillResponse) } if (!validFillResponse) { @@ -229,7 +229,7 @@ class CredentialAutofillService : AutofillService() { providerDataList: ArrayList<GetCredentialProviderData>, entryIconMap: Map<String, Icon>, fillResponseBuilder: FillResponse.Builder, - bottomSheetPendingIntent: PendingIntent? + bottomSheetIntent: Intent ): Boolean { val providerList = GetFlowUtils.toProviderList( providerDataList, @@ -267,6 +267,8 @@ class CredentialAutofillService : AutofillService() { } } } + bottomSheetIntent.putExtra( + ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, providerDataList) providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@{ val primaryEntry = it.sortedCredentialEntryList.first() val pendingIntent = primaryEntry.pendingIntent @@ -330,16 +332,16 @@ class CredentialAutofillService : AutofillService() { datasetAdded = true i++ - if (i == lastDropdownDatasetIndex && bottomSheetPendingIntent != null) { - addDropdownMoreOptionsPresentation(bottomSheetPendingIntent, autofillId, + if (i == lastDropdownDatasetIndex) { + addDropdownMoreOptionsPresentation(bottomSheetIntent, autofillId, fillResponseBuilder) } } val pinnedSpec = getLastInlinePresentationSpec(inlinePresentationSpecs, inlinePresentationSpecsCount) - if (datasetAdded && bottomSheetPendingIntent != null && pinnedSpec != null) { - addPinnedInlineSuggestion(bottomSheetPendingIntent, pinnedSpec, autofillId, - fillResponseBuilder, providerDataList) + if (datasetAdded && pinnedSpec != null) { + addPinnedInlineSuggestion(pinnedSpec, autofillId, + fillResponseBuilder, bottomSheetIntent) } return datasetAdded } @@ -370,13 +372,14 @@ class CredentialAutofillService : AutofillService() { } private fun addDropdownMoreOptionsPresentation( - bottomSheetPendingIntent: PendingIntent, + bottomSheetIntent: Intent, autofillId: AutofillId, fillResponseBuilder: FillResponse.Builder ) { val presentationBuilder = Presentations.Builder() .setMenuPresentation( RemoteViewsFactory.createMoreSignInOptionsPresentation(this)) + val pendingIntent = setUpBottomSheetPendingIntent(bottomSheetIntent) fillResponseBuilder.addDataset( Dataset.Builder() @@ -385,7 +388,7 @@ class CredentialAutofillService : AutofillService() { Field.Builder().setPresentations( presentationBuilder.build()) .build()) - .setAuthentication(bottomSheetPendingIntent.intentSender) + .setAuthentication(pendingIntent.intentSender) .build() ) } @@ -401,37 +404,41 @@ class CredentialAutofillService : AutofillService() { } private fun addPinnedInlineSuggestion( - bottomSheetPendingIntent: PendingIntent, spec: InlinePresentationSpec, autofillId: AutofillId, fillResponseBuilder: FillResponse.Builder, - providerDataList: ArrayList<GetCredentialProviderData> + bottomSheetIntent: Intent ) { + val pendingIntent = setUpBottomSheetPendingIntent(bottomSheetIntent) + val dataSetBuilder = Dataset.Builder() val sliceBuilder = InlineSuggestionUi - .newContentBuilder(bottomSheetPendingIntent) + .newContentBuilder(pendingIntent) .setStartIcon(Icon.createWithResource(this, com.android.credentialmanager.R.drawable.more_horiz_24px)) val presentationBuilder = Presentations.Builder() .setInlinePresentation(InlinePresentation( sliceBuilder.build().slice, spec, /* pinned= */ true)) - val extrasIntent = Intent() - extrasIntent.putExtra(ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, providerDataList) - fillResponseBuilder.addDataset( dataSetBuilder .setField( autofillId, Field.Builder().setPresentations( - presentationBuilder.build()) - .build()) - .setAuthentication(bottomSheetPendingIntent.intentSender) - .setCredentialFillInIntent(extrasIntent) + presentationBuilder.build() + ).build() + ) + .setAuthentication(pendingIntent.intentSender) .build() ) } + private fun setUpBottomSheetPendingIntent(intent: Intent): PendingIntent { + intent.setAction(java.util.UUID.randomUUID().toString()) + return PendingIntent.getActivity(this, /*requestCode=*/0, intent, + PendingIntent.FLAG_MUTABLE, /*options=*/null) + } + /** * Maps Autofill Id to provider list. For example, passing in a provider info * @@ -571,7 +578,7 @@ class CredentialAutofillService : AutofillService() { responseClientState: Bundle ): GetCredentialRequest? { val credentialOptions: MutableList<CredentialOption> = mutableListOf() - traverseStructureForRequest(structure, credentialOptions, responseClientState) + traverseStructureForRequest(structure, credentialOptions, responseClientState, sessionId) if (credentialOptions.isNotEmpty()) { val dataBundle = Bundle() @@ -587,7 +594,8 @@ class CredentialAutofillService : AutofillService() { private fun traverseStructureForRequest( structure: AssistStructure, cmRequests: MutableList<CredentialOption>, - responseClientState: Bundle + responseClientState: Bundle, + sessionId: Int ) { val traversedViewNodes: MutableSet<AutofillId> = mutableSetOf() val credentialOptionsFromHints: MutableMap<String, CredentialOption> = mutableMapOf() @@ -599,7 +607,7 @@ class CredentialAutofillService : AutofillService() { windowNodes.forEach { windowNode: AssistStructure.WindowNode -> traverseNodeForRequest( windowNode.rootViewNode, cmRequests, responseClientState, traversedViewNodes, - credentialOptionsFromHints) + credentialOptionsFromHints, sessionId) } } @@ -608,11 +616,12 @@ class CredentialAutofillService : AutofillService() { cmRequests: MutableList<CredentialOption>, responseClientState: Bundle, traversedViewNodes: MutableSet<AutofillId>, - credentialOptionsFromHints: MutableMap<String, CredentialOption> + credentialOptionsFromHints: MutableMap<String, CredentialOption>, + sessionId: Int ) { viewNode.autofillId?.let { cmRequests.addAll(getCredentialOptionsFromViewNode(viewNode, it, responseClientState, - traversedViewNodes, credentialOptionsFromHints)) + traversedViewNodes, credentialOptionsFromHints, sessionId)) traversedViewNodes.add(it) } @@ -623,7 +632,7 @@ class CredentialAutofillService : AutofillService() { children.forEach { childNode: AssistStructure.ViewNode -> traverseNodeForRequest(childNode, cmRequests, responseClientState, traversedViewNodes, - credentialOptionsFromHints) + credentialOptionsFromHints, sessionId) } } @@ -632,7 +641,8 @@ class CredentialAutofillService : AutofillService() { autofillId: AutofillId, responseClientState: Bundle, traversedViewNodes: MutableSet<AutofillId>, - credentialOptionsFromHints: MutableMap<String, CredentialOption> + credentialOptionsFromHints: MutableMap<String, CredentialOption>, + sessionId: Int ): MutableList<CredentialOption> { val credentialOptions: MutableList<CredentialOption> = mutableListOf() if (Flags.autofillCredmanDevIntegration() && viewNode.credentialManagerRequest != null) { @@ -643,12 +653,25 @@ class CredentialAutofillService : AutofillService() { .getParcelableArrayList( CredentialProviderService.EXTRA_AUTOFILL_ID, AutofillId::class.java) ?.let { associatedAutofillIds -> + // Set sessionId in autofillIds. The autofillIds stored in Credential + // Options do not have associated session id and will result in + // different hashes than the ones in assistStructure. + associatedAutofillIds.forEach { associatedAutofillId -> + associatedAutofillId.sessionId = sessionId + } + // Check whether any of the associated autofill ids have already been // traversed. If so, skip, to dedupe on duplicate credential options. if ((traversedViewNodes intersect associatedAutofillIds.toSet()) .isEmpty()) { credentialOptions.add(credentialOption) } + + // Set the autofillIds with session id back to credential option. + credentialOption.candidateQueryData.putParcelableArrayList( + CredentialProviderService.EXTRA_AUTOFILL_ID, + associatedAutofillIds + ) } } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt index d319e4cc9ef9..a7b5c36215cf 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt @@ -16,8 +16,15 @@ package com.android.credentialmanager.common.ui +import android.credentials.flags.Flags +import androidx.compose.animation.animateContentSize import androidx.compose.foundation.background -import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope @@ -25,6 +32,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import com.android.compose.rememberSystemUiController import com.android.compose.theme.LocalAndroidColorScheme +import androidx.compose.ui.unit.dp import com.android.credentialmanager.common.material.ModalBottomSheetLayout import com.android.credentialmanager.common.material.ModalBottomSheetValue import com.android.credentialmanager.common.material.rememberModalBottomSheetState @@ -34,40 +42,68 @@ import kotlinx.coroutines.launch /** Draws a modal bottom sheet with the same styles and effects shared by various flows. */ @Composable +@OptIn(ExperimentalMaterial3Api::class) fun ModalBottomSheet( - sheetContent: @Composable ColumnScope.() -> Unit, - onDismiss: () -> Unit, - isInitialRender: Boolean, - onInitialRenderComplete: () -> Unit, - isAutoSelectFlow: Boolean, + sheetContent: @Composable () -> Unit, + onDismiss: () -> Unit, + isInitialRender: Boolean, + onInitialRenderComplete: () -> Unit, + isAutoSelectFlow: Boolean, ) { - val scope = rememberCoroutineScope() - val state = rememberModalBottomSheetState( - initialValue = if (isAutoSelectFlow) ModalBottomSheetValue.Expanded - else ModalBottomSheetValue.Hidden, - skipHalfExpanded = true - ) - val sysUiController = rememberSystemUiController() - if (state.targetValue == ModalBottomSheetValue.Hidden || isAutoSelectFlow) { - setTransparentSystemBarsColor(sysUiController) + if (Flags.selectorUiImprovementsEnabled()) { + val state = androidx.compose.material3.rememberModalBottomSheetState( + skipPartiallyExpanded = true + ) + androidx.compose.material3.ModalBottomSheet( + onDismissRequest = onDismiss, + containerColor = LocalAndroidColorScheme.current.surfaceBright, + sheetState = state, + content = { + Box( + modifier = Modifier + .animateContentSize() + .wrapContentHeight() + .fillMaxWidth() + ) { + sheetContent() + } + }, + scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = .32f), + shape = EntryShape.TopRoundedCorner, + dragHandle = null, + // Never take over the full screen. We always want to leave some top scrim space + // for exiting and viewing the underlying app to help a user gain context. + modifier = Modifier.padding(top = 56.dp), + ) } else { - setBottomSheetSystemBarsColor(sysUiController) - } - ModalBottomSheetLayout( - sheetBackgroundColor = LocalAndroidColorScheme.current.surfaceBright, - modifier = Modifier.background(Color.Transparent), - sheetState = state, - sheetContent = sheetContent, - sheetShape = EntryShape.TopRoundedCorner, - ) {} - LaunchedEffect(state.currentValue, state.targetValue) { - if (state.currentValue == ModalBottomSheetValue.Hidden) { - if (isInitialRender) { - onInitialRenderComplete() - scope.launch { state.show() } - } else if (state.targetValue == ModalBottomSheetValue.Hidden) { - // Only dismiss ui when the motion is downwards - onDismiss() + val scope = rememberCoroutineScope() + val state = rememberModalBottomSheetState( + initialValue = if (isAutoSelectFlow) ModalBottomSheetValue.Expanded + else ModalBottomSheetValue.Hidden, + skipHalfExpanded = true + ) + val sysUiController = rememberSystemUiController() + if (state.targetValue == ModalBottomSheetValue.Hidden || isAutoSelectFlow) { + setTransparentSystemBarsColor(sysUiController) + } else { + setBottomSheetSystemBarsColor(sysUiController) + } + ModalBottomSheetLayout( + sheetBackgroundColor = LocalAndroidColorScheme.current.surfaceBright, + modifier = Modifier.background(Color.Transparent), + sheetState = state, + sheetContent = { sheetContent() }, + sheetShape = EntryShape.TopRoundedCorner, + ) {} + LaunchedEffect(state.currentValue, state.targetValue) { + if (state.currentValue == ModalBottomSheetValue.Hidden) { + if (isInitialRender) { + onInitialRenderComplete() + scope.launch { state.show() } + } else if (state.targetValue == ModalBottomSheetValue.Hidden) { + // Only dismiss ui when the motion is downwards + onDismiss() + } } } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt index bdfe39920d44..c68ae8b168fb 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt @@ -18,7 +18,10 @@ package com.android.credentialmanager.common.ui import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.LazyColumn @@ -66,6 +69,9 @@ fun SheetContainerCard( horizontalAlignment = Alignment.CenterHorizontally, content = content, verticalArrangement = contentVerticalArrangement, + // The bottom sheet overlaps with the navigation bars but make sure the actual content + // in the bottom sheet does not. + contentPadding = WindowInsets.navigationBars.asPaddingValues(), ) } } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt index a6253b8d4e07..8ff17e0d333a 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt @@ -29,13 +29,10 @@ import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.outlined.Lock -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.SuggestionChip import androidx.compose.material3.SuggestionChipDefaults -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -278,31 +275,6 @@ fun ActionEntry( } /** - * A single row of leading icon and text describing a benefit of passkeys, used by the - * [com.android.credentialmanager.createflow.PasskeyIntroCard]. - */ -@Composable -fun PasskeyBenefitRow( - leadingIconPainter: Painter, - text: String, -) { - Row( - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.fillMaxWidth() - ) { - Icon( - modifier = Modifier.size(24.dp), - painter = leadingIconPainter, - tint = LocalAndroidColorScheme.current.onSurfaceVariant, - // Decorative purpose only. - contentDescription = null, - ) - BodyMediumText(text = text) - } -} - -/** * A single row of one or two CTA buttons for continuing or cancelling the current step. */ @Composable @@ -327,40 +299,36 @@ fun CtaButtonRow( } } -@OptIn(ExperimentalMaterial3Api::class) @Composable fun MoreOptionTopAppBar( text: String, onNavigationIconClicked: () -> Unit, bottomPadding: Dp, ) { - TopAppBar( - title = { - LargeTitleText(text = text, modifier = Modifier.padding(horizontal = 4.dp)) - }, - navigationIcon = { - IconButton( + Row( + modifier = Modifier.padding(top = 12.dp, bottom = bottomPadding), + verticalAlignment = Alignment.CenterVertically, + ) { + IconButton( modifier = Modifier.padding(top = 8.dp, bottom = 8.dp, start = 4.dp).size(48.dp), onClick = onNavigationIconClicked - ) { - Box( + ) { + Box( modifier = Modifier.size(48.dp), contentAlignment = Alignment.Center, - ) { - Icon( + ) { + Icon( imageVector = Icons.Filled.ArrowBack, contentDescription = stringResource( - R.string.accessibility_back_arrow_button + R.string.accessibility_back_arrow_button ), modifier = Modifier.size(24.dp).autoMirrored(), tint = LocalAndroidColorScheme.current.onSurfaceVariant, - ) - } + ) } - }, - colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent), - modifier = Modifier.padding(top = 12.dp, bottom = bottomPadding) - ) + } + LargeTitleText(text = text, modifier = Modifier.padding(horizontal = 4.dp)) + } } private fun Modifier.autoMirrored() = composed { diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt index 4ed84b908865..72775500e7c5 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt @@ -653,4 +653,4 @@ fun EmptyAuthEntrySnackBarScreen( contentText = stringResource(R.string.no_sign_in_info_in, lastLocked.providerDisplayName), ) onLog(GetCredentialEvent.CREDMAN_GET_CRED_SCREEN_EMPTY_AUTH_SNACKBAR_SCREEN) -}
\ No newline at end of file +} diff --git a/packages/CredentialManager/tests/robotests/Android.bp b/packages/CredentialManager/tests/robotests/Android.bp index baebfeb399f2..75a0dcce0b9e 100644 --- a/packages/CredentialManager/tests/robotests/Android.bp +++ b/packages/CredentialManager/tests/robotests/Android.bp @@ -37,7 +37,7 @@ android_robolectric_test { ":CredentialManagerScreenshotTestFiles", ], - // Do not add any libraries here, instead add them to the ScreenshotTestStub + // Do not add any libraries here, instead add them to the ScreenshotTestRobo static_libs: [ "androidx.compose.runtime_runtime", "androidx.test.uiautomator_uiautomator", @@ -45,6 +45,7 @@ android_robolectric_test { "inline-mockito-robolectric-prebuilt", "platform-parametric-runner-lib", "uiautomator-helpers", + "flag-junit-base", ], libs: [ "android.test.runner", diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..81860e538275 --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_portrait_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..8c1fff7df8ab --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_portrait_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/light_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_landscape_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..4eb025fcd190 --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_landscape_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/light_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_portrait_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..c709f934f78d --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_portrait_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_landscape_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..278c13f6c7da --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_landscape_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_portrait_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..cb85df350ccf --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_portrait_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_landscape_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..2eca70741a3c --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_landscape_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_portrait_singleCredentialScreen_newM3BottomSheet.png Binary files differnew file mode 100644 index 000000000000..7ee91b3705df --- /dev/null +++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_portrait_singleCredentialScreen_newM3BottomSheet.png diff --git a/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt b/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt index a0e1fed0ac96..e609d0c5c008 100644 --- a/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt +++ b/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt @@ -16,7 +16,10 @@ package com.android.credentialmanager +import android.credentials.flags.Flags import android.content.Context +import android.platform.test.flag.junit.SetFlagsRule +import androidx.compose.ui.test.isPopup import com.android.credentialmanager.getflow.RequestDisplayInfo import com.android.credentialmanager.model.CredentialType import com.android.credentialmanager.model.get.ProviderInfo @@ -59,8 +62,11 @@ class GetCredScreenshotTest(emulationSpec: DeviceEmulationSpec) { CredentialManagerGoldenImagePathManager(getEmulatedDevicePathConfig(emulationSpec)) ) + @get:Rule val setFlagsRule: SetFlagsRule = SetFlagsRule() + @Test - fun singleCredentialScreen() { + fun singleCredentialScreen_M3BottomSheetDisabled() { + setFlagsRule.disableFlags(Flags.FLAG_SELECTOR_UI_IMPROVEMENTS_ENABLED) val providerInfoList = buildProviderInfoList() val providerDisplayInfo = toProviderDisplayInfo(providerInfoList) val activeEntry = toActiveEntry(providerDisplayInfo) @@ -86,6 +92,39 @@ class GetCredScreenshotTest(emulationSpec: DeviceEmulationSpec) { } } + @Test + fun singleCredentialScreen_M3BottomSheetEnabled() { + setFlagsRule.enableFlags(Flags.FLAG_SELECTOR_UI_IMPROVEMENTS_ENABLED) + val providerInfoList = buildProviderInfoList() + val providerDisplayInfo = toProviderDisplayInfo(providerInfoList) + val activeEntry = toActiveEntry(providerDisplayInfo) + screenshotRule.screenshotTest( + "singleCredentialScreen_newM3BottomSheet", + // M3's ModalBottomSheet lives in a new window, meaning we have two windows with + // a root. Hence use a different matcher `isPopup`. + viewFinder = { screenshotRule.composeRule.onNode(isPopup()) }, + ) { + ModalBottomSheet( + sheetContent = { + PrimarySelectionCard( + requestDisplayInfo = REQUEST_DISPLAY_INFO, + providerDisplayInfo = providerDisplayInfo, + providerInfoList = providerInfoList, + activeEntry = activeEntry, + onEntrySelected = {}, + onConfirm = {}, + onMoreOptionSelected = {}, + onLog = {}, + ) + }, + isInitialRender = true, + onDismiss = {}, + onInitialRenderComplete = {}, + isAutoSelectFlow = false, + ) + } + } + private fun buildProviderInfoList(): List<ProviderInfo> { val context = ApplicationProvider.getApplicationContext<Context>() val provider1 = ProviderInfo( diff --git a/packages/FusedLocation/AndroidManifest.xml b/packages/FusedLocation/AndroidManifest.xml index 05561d79c3d5..158c33ae2035 100644 --- a/packages/FusedLocation/AndroidManifest.xml +++ b/packages/FusedLocation/AndroidManifest.xml @@ -28,6 +28,7 @@ <uses-permission android:name="android.permission.INSTALL_LOCATION_PROVIDER" /> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> + <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /> <application android:label="@string/app_label" @@ -49,5 +50,17 @@ <meta-data android:name="serviceVersion" android:value="0" /> <meta-data android:name="serviceIsMultiuser" android:value="true" /> </service> + + <!-- GNSS overlay Service that LocationManagerService binds to. + LocationManagerService will bind to the service with the highest + version. --> + <service android:name="com.android.location.gnss.GnssOverlayLocationService" + android:exported="false"> + <intent-filter> + <action android:name="android.location.provider.action.GNSS_PROVIDER" /> + </intent-filter> + <meta-data android:name="serviceVersion" android:value="0" /> + <meta-data android:name="serviceIsMultiuser" android:value="true" /> + </service> </application> </manifest> diff --git a/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java b/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java new file mode 100644 index 000000000000..c6576e39de99 --- /dev/null +++ b/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.location.gnss; + +import static android.location.provider.ProviderProperties.ACCURACY_FINE; +import static android.location.provider.ProviderProperties.POWER_USAGE_HIGH; + +import android.annotation.Nullable; +import android.content.Context; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.location.LocationRequest; +import android.location.provider.LocationProviderBase; +import android.location.provider.ProviderProperties; +import android.location.provider.ProviderRequest; +import android.os.Bundle; +import android.util.SparseArray; + + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.ConcurrentUtils; + +import java.util.List; + +/** Basic pass-through GNSS location provider implementation. */ +public class GnssOverlayLocationProvider extends LocationProviderBase { + + private static final String TAG = "GnssOverlay"; + + private static final ProviderProperties PROPERTIES = new ProviderProperties.Builder() + .setHasAltitudeSupport(true) + .setHasSpeedSupport(true) + .setHasBearingSupport(true) + .setPowerUsage(POWER_USAGE_HIGH) + .setAccuracy(ACCURACY_FINE) + .build(); + + @GuardedBy("mPendingFlushes") + private final SparseArray<OnFlushCompleteCallback> mPendingFlushes = new SparseArray<>(); + + private final LocationManager mLocationManager; + + private final GnssLocationListener mGnssLocationListener = new GnssLocationListener(); + + @GuardedBy("mPendingFlushes") + private int mFlushCode = 0; + + /** Location listener for receiving locations from LocationManager. */ + private class GnssLocationListener implements LocationListener { + @Override + public void onLocationChanged(Location location) { + reportLocation(location); + } + + @Override + public void onLocationChanged(List<Location> locations) { + reportLocations(locations); + } + + @Override + public void onFlushComplete(int requestCode) { + OnFlushCompleteCallback flushCompleteCallback; + synchronized (mPendingFlushes) { + flushCompleteCallback = mPendingFlushes.get(requestCode); + mPendingFlushes.remove(requestCode); + } + if (flushCompleteCallback != null) { + flushCompleteCallback.onFlushComplete(); + } + } + } + + public GnssOverlayLocationProvider(Context context) { + super(context, TAG, PROPERTIES); + mLocationManager = context.getSystemService(LocationManager.class); + } + + void start() { + } + + void stop() { + mLocationManager.removeUpdates(mGnssLocationListener); + } + + @Override + public void onSendExtraCommand(String command, @Nullable Bundle extras) { + mLocationManager.sendExtraCommand(LocationManager.GPS_HARDWARE_PROVIDER, command, extras); + } + + @Override + public void onFlush(OnFlushCompleteCallback callback) { + int flushCodeCopy; + synchronized (mPendingFlushes) { + flushCodeCopy = mFlushCode++; + mPendingFlushes.put(flushCodeCopy, callback); + } + mLocationManager.requestFlush( + LocationManager.GPS_HARDWARE_PROVIDER, mGnssLocationListener, flushCodeCopy); + } + + @Override + public void onSetRequest(ProviderRequest request) { + if (request.isActive()) { + mLocationManager.requestLocationUpdates( + LocationManager.GPS_HARDWARE_PROVIDER, + new LocationRequest.Builder(request.getIntervalMillis()) + .setMaxUpdateDelayMillis(request.getMaxUpdateDelayMillis()) + .setLowPower(request.isLowPower()) + .setLocationSettingsIgnored(request.isLocationSettingsIgnored()) + .setWorkSource(request.getWorkSource()) + .setQuality(request.getQuality()) + .build(), + ConcurrentUtils.DIRECT_EXECUTOR, + mGnssLocationListener); + } else { + mLocationManager.removeUpdates(mGnssLocationListener); + } + } +} diff --git a/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationService.java b/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationService.java new file mode 100644 index 000000000000..dd034fec9495 --- /dev/null +++ b/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationService.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.location.gnss; + +import android.annotation.Nullable; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +public class GnssOverlayLocationService extends Service { + + @Nullable private GnssOverlayLocationProvider mProvider; + + @Override + public IBinder onBind(Intent intent) { + if (mProvider == null) { + mProvider = new GnssOverlayLocationProvider(this); + mProvider.start(); + } + + return mProvider.getBinder(); + } + + @Override + public void onDestroy() { + if (mProvider != null) { + mProvider.stop(); + mProvider = null; + } + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + } +} diff --git a/packages/FusedLocation/test/src/com/android/location/gnss/tests/GnssOverlayLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/gnss/tests/GnssOverlayLocationServiceTest.java new file mode 100644 index 000000000000..5b33deb60759 --- /dev/null +++ b/packages/FusedLocation/test/src/com/android/location/gnss/tests/GnssOverlayLocationServiceTest.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.location.gnss.tests; + +import static android.location.LocationManager.GPS_HARDWARE_PROVIDER; + +import static androidx.test.ext.truth.location.LocationSubject.assertThat; + +import android.content.Context; +import android.location.Criteria; +import android.location.Location; +import android.location.LocationManager; +import android.location.LocationRequest; +import android.location.provider.ILocationProvider; +import android.location.provider.ILocationProviderManager; +import android.location.provider.ProviderProperties; +import android.location.provider.ProviderRequest; +import android.os.ParcelFileDescriptor; +import android.os.SystemClock; +import android.util.Log; + +import androidx.test.InstrumentationRegistry; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.runner.AndroidJUnit4; + +import com.android.location.gnss.GnssOverlayLocationProvider; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.List; +import java.util.Random; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +public class GnssOverlayLocationServiceTest { + + private static final String TAG = "GnssOverlayLocationServiceTest"; + + private static final long TIMEOUT_MS = 5000; + + private Random mRandom; + private LocationManager mLocationManager; + + private ILocationProvider mProvider; + private LocationProviderManagerCapture mManager; + + @Before + public void setUp() throws Exception { + long seed = System.currentTimeMillis(); + Log.i(TAG, "location seed: " + seed); + + Context context = ApplicationProvider.getApplicationContext(); + mRandom = new Random(seed); + mLocationManager = context.getSystemService(LocationManager.class); + + setMockLocation(true); + + mManager = new LocationProviderManagerCapture(); + mProvider = ILocationProvider.Stub.asInterface( + new GnssOverlayLocationProvider(context).getBinder()); + mProvider.setLocationProviderManager(mManager); + + mLocationManager.addTestProvider(GPS_HARDWARE_PROVIDER, + true, + false, + true, + false, + false, + false, + false, + Criteria.POWER_MEDIUM, + Criteria.ACCURACY_FINE); + mLocationManager.setTestProviderEnabled(GPS_HARDWARE_PROVIDER, true); + } + + @After + public void tearDown() throws Exception { + for (String provider : mLocationManager.getAllProviders()) { + mLocationManager.removeTestProvider(provider); + } + + setMockLocation(false); + } + + @Test + public void testGpsRequest() throws Exception { + mProvider.setRequest( + new ProviderRequest.Builder() + .setQuality(LocationRequest.QUALITY_HIGH_ACCURACY) + .setIntervalMillis(1000) + .build()); + + Location location = createLocation(GPS_HARDWARE_PROVIDER, mRandom); + mLocationManager.setTestProviderLocation(GPS_HARDWARE_PROVIDER, location); + + assertThat(mManager.getNextLocation(TIMEOUT_MS)).isEqualTo(location); + } + + private static class LocationProviderManagerCapture extends ILocationProviderManager.Stub { + + private final LinkedBlockingQueue<Location> mLocations; + + private LocationProviderManagerCapture() { + mLocations = new LinkedBlockingQueue<>(); + } + + @Override + public void onInitialize(boolean allowed, ProviderProperties properties, + String attributionTag) {} + + @Override + public void onSetAllowed(boolean allowed) {} + + @Override + public void onSetProperties(ProviderProperties properties) {} + + @Override + public void onReportLocation(Location location) { + mLocations.add(location); + } + + @Override + public void onReportLocations(List<Location> locations) { + mLocations.addAll(locations); + } + + @Override + public void onFlushComplete() {} + + public Location getNextLocation(long timeoutMs) throws InterruptedException { + return mLocations.poll(timeoutMs, TimeUnit.MILLISECONDS); + } + } + + private static final double MIN_LATITUDE = -90D; + private static final double MAX_LATITUDE = 90D; + private static final double MIN_LONGITUDE = -180D; + private static final double MAX_LONGITUDE = 180D; + + private static final float MIN_ACCURACY = 1; + private static final float MAX_ACCURACY = 100; + + private static Location createLocation(String provider, Random random) { + return createLocation(provider, + MIN_LATITUDE + random.nextDouble() * (MAX_LATITUDE - MIN_LATITUDE), + MIN_LONGITUDE + random.nextDouble() * (MAX_LONGITUDE - MIN_LONGITUDE), + MIN_ACCURACY + random.nextFloat() * (MAX_ACCURACY - MIN_ACCURACY)); + } + + private static Location createLocation(String provider, double latitude, double longitude, + float accuracy) { + Location location = new Location(provider); + location.setLatitude(latitude); + location.setLongitude(longitude); + location.setAccuracy(accuracy); + location.setTime(System.currentTimeMillis()); + location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); + return location; + } + + private static void setMockLocation(boolean allowed) throws IOException { + ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation() + .executeShellCommand("appops set " + + InstrumentationRegistry.getTargetContext().getPackageName() + + " android:mock_location " + (allowed ? "allow" : "deny")); + try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + byte[] buffer = new byte[32768]; + int count; + try { + while ((count = fis.read(buffer)) != -1) { + os.write(buffer, 0, count); + } + fis.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + Log.e(TAG, new String(os.toByteArray())); + } + } +} diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java index 904e1843dd44..cf6aab641fc9 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java @@ -403,7 +403,7 @@ public class PackageInstallerActivity extends Activity { resolvedPath = info.getResolvedBaseApkPath(); } if (info == null || !info.isSealed() || resolvedPath == null) { - Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring"); + Log.w(TAG, "Session " + sessionId + " in funky state; ignoring"); finish(); return; } @@ -418,7 +418,7 @@ public class PackageInstallerActivity extends Activity { -1 /* defaultValue */); final SessionInfo info = mInstaller.getSessionInfo(sessionId); if (info == null || !info.isPreApprovalRequested()) { - Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring"); + Log.w(TAG, "Session " + sessionId + " in funky state; ignoring"); finish(); return; } @@ -839,7 +839,9 @@ public class PackageInstallerActivity extends Activity { // work for the multiple user case, i.e. the caller task user and started // Activity user are not the same. To avoid having multiple PIAs in the task, // finish the current PackageInstallerActivity - finish(); + // Because finish() is overridden to set the installation result, we must use + // the original finish() method, or the confirmation dialog fails to appear. + PackageInstallerActivity.super.finish(); } }, 500); diff --git a/packages/SettingsLib/Spa/build.gradle.kts b/packages/SettingsLib/Spa/build.gradle.kts index 463e9be391b6..335725cdad5e 100644 --- a/packages/SettingsLib/Spa/build.gradle.kts +++ b/packages/SettingsLib/Spa/build.gradle.kts @@ -29,7 +29,7 @@ val androidTop: String = File(rootDir, "../../../../..").canonicalPath allprojects { extra["androidTop"] = androidTop - extra["jetpackComposeVersion"] = "1.7.0-alpha02" + extra["jetpackComposeVersion"] = "1.7.0-alpha03" } subprojects { diff --git a/packages/SettingsLib/Spa/gradle/libs.versions.toml b/packages/SettingsLib/Spa/gradle/libs.versions.toml index fe378c27523c..609a82e79827 100644 --- a/packages/SettingsLib/Spa/gradle/libs.versions.toml +++ b/packages/SettingsLib/Spa/gradle/libs.versions.toml @@ -16,7 +16,7 @@ [versions] agp = "8.2.2" -compose-compiler = "1.5.9" +compose-compiler = "1.5.10" dexmaker-mockito = "2.28.3" jvm = "17" kotlin = "1.9.22" diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_slider.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_slider.png Binary files differindex a038779b0e79..e1f5c742dab7 100644 --- a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_slider.png +++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_slider.png diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_slider.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_slider.png Binary files differindex 03db688f6799..928e9268292b 100644 --- a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_slider.png +++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_slider.png diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_slider.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_slider.png Binary files differindex 1345c379cfb0..05213688b0a8 100644 --- a/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_slider.png +++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_slider.png diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts index 2259bd74d56e..a193a2f9970d 100644 --- a/packages/SettingsLib/Spa/spa/build.gradle.kts +++ b/packages/SettingsLib/Spa/spa/build.gradle.kts @@ -57,7 +57,7 @@ dependencies { api("androidx.slice:slice-builders:1.1.0-alpha02") api("androidx.slice:slice-core:1.1.0-alpha02") api("androidx.slice:slice-view:1.1.0-alpha02") - api("androidx.compose.material3:material3:1.2.0") + api("androidx.compose.material3:material3:1.3.0-alpha01") api("androidx.compose.material:material-icons-extended:$jetpackComposeVersion") api("androidx.compose.runtime:runtime-livedata:$jetpackComposeVersion") api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion") diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt new file mode 100644 index 000000000000..8300ce855988 --- /dev/null +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.spa.widget.preference + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.selection.selectable +import androidx.compose.foundation.selection.selectableGroup +import androidx.compose.material3.RadioButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.semantics.Role +import com.android.settingslib.spa.framework.theme.SettingsDimension +import com.android.settingslib.spa.widget.ui.CategoryTitle +import com.android.settingslib.spa.widget.ui.SettingsListItem + +@Composable +fun RadioPreferences(model: ListPreferenceModel) { + CategoryTitle(title = model.title) + Spacer(modifier = Modifier.width(SettingsDimension.itemDividerHeight)) + Column(modifier = Modifier.selectableGroup()) { + for (option in model.options) { + Radio2(option, model.selectedId.intValue, model.enabled()) { + model.onIdSelected(it) + } + } + } +} + +@Composable +fun Radio2( + option: ListPreferenceOption, + selectedId: Int, + enabled: Boolean, + onIdSelected: (id: Int) -> Unit, +) { + val selected = option.id == selectedId + Row( + modifier = Modifier + .fillMaxWidth() + .selectable( + selected = selected, + enabled = enabled, + onClick = { onIdSelected(option.id) }, + role = Role.RadioButton, + ) + .padding(SettingsDimension.dialogItemPadding), + verticalAlignment = Alignment.CenterVertically, + ) { + RadioButton(selected = selected, onClick = null, enabled = enabled) + Spacer(modifier = Modifier.width(SettingsDimension.itemDividerHeight)) + SettingsListItem(text = option.text, enabled = enabled) + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt index 4f6196648634..56534f41c3df 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt @@ -180,7 +180,7 @@ private class TopAppBarColors( * @param colorTransitionFraction a `0.0` to `1.0` value that represents a color transition * percentage */ - @Composable + @Stable fun containerColor(colorTransitionFraction: Float): Color { return lerp( containerColor, @@ -519,7 +519,7 @@ private fun TopAppBarLayout( 0 } - val layoutHeight = if (heightPx.isNaN()) 0 else heightPx.roundToInt() + val layoutHeight = if (heightPx > 0) heightPx.roundToInt() else 0 layout(constraints.maxWidth, layoutHeight) { // Navigation icon diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt index b4a6a0d00720..a59b95a60879 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt @@ -66,6 +66,19 @@ fun SettingsDialogItem(text: String, enabled: Boolean = true) { } @Composable +fun SettingsListItem(text: String, enabled: Boolean = true) { + Text( + text = text, + modifier = Modifier + .alphaForEnabled(enabled) + .padding(vertical = SettingsDimension.paddingTiny), + color = MaterialTheme.colorScheme.onSurface, + style = MaterialTheme.typography.titleMedium, + overflow = TextOverflow.Ellipsis, + ) +} + +@Composable fun SettingsBody( body: String, maxLines: Int = Int.MAX_VALUE, diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt new file mode 100644 index 000000000000..2f98b02b8dd5 --- /dev/null +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.spa.widget.preference + +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertIsNotEnabled +import androidx.compose.ui.test.assertIsNotSelected +import androidx.compose.ui.test.assertIsSelectable +import androidx.compose.ui.test.assertIsSelected +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 org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class RadioPreferencesTest { + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun title_displayed() { + composeTestRule.setContent { + RadioPreferences(remember { + object : ListPreferenceModel { + override val title = TITLE + override val options = emptyList<ListPreferenceOption>() + override val selectedId = mutableIntStateOf(0) + override val onIdSelected: (Int) -> Unit = {} + } + }) + } + composeTestRule.onNodeWithText(TITLE).assertIsDisplayed() + } + + @Test + fun item_displayed() { + val selectedId = mutableIntStateOf(1) + composeTestRule.setContent { + RadioPreferences(remember { + object : ListPreferenceModel { + override val title = TITLE + override val options = listOf( + ListPreferenceOption(id = 1, text = "A"), + ListPreferenceOption(id = 2, text = "B"), + ) + override val selectedId = selectedId + override val onIdSelected = { id: Int -> selectedId.intValue = id } + } + }) + } + composeTestRule.onNodeWithText("A").assertIsDisplayed() + composeTestRule.onNodeWithText("B").assertIsDisplayed() + } + + @Test + fun item_selectable() { + val selectedId = mutableIntStateOf(1) + val enabledState = mutableStateOf(true) + composeTestRule.setContent { + RadioPreferences(remember { + object : ListPreferenceModel { + override val title = TITLE + override val enabled = { enabledState.value } + override val options = listOf( + ListPreferenceOption(id = 1, text = "A"), + ListPreferenceOption(id = 2, text = "B"), + ) + override val selectedId = selectedId + override val onIdSelected = { id: Int -> selectedId.intValue = id } + } + }) + } + composeTestRule.onNodeWithText("A").assertIsSelectable() + composeTestRule.onNodeWithText("B").assertIsSelectable() + } + + @Test + fun item_single_selected() { + val selectedId = mutableIntStateOf(1) + val enabledState = mutableStateOf(true) + composeTestRule.setContent { + RadioPreferences(remember { + object : ListPreferenceModel { + override val title = TITLE + override val enabled = { enabledState.value } + override val options = listOf( + ListPreferenceOption(id = 1, text = "A"), + ListPreferenceOption(id = 2, text = "B"), + ) + override val selectedId = selectedId + override val onIdSelected = { id: Int -> selectedId.intValue = id } + } + }) + } + composeTestRule.onNodeWithText("B").assertIsSelectable() + composeTestRule.onNodeWithText("B").performClick() + composeTestRule.onNodeWithText("B").assertIsSelected() + composeTestRule.onNodeWithText("A").assertIsNotSelected() + composeTestRule.onNodeWithText("A").performClick() + composeTestRule.onNodeWithText("A").assertIsSelected() + composeTestRule.onNodeWithText("B").assertIsNotSelected() + } + + @Test + fun select_itemDisabled() { + val selectedId = mutableIntStateOf(1) + val enabledState = mutableStateOf(true) + composeTestRule.setContent { + RadioPreferences(remember { + object : ListPreferenceModel { + override val title = TITLE + override val enabled = { enabledState.value } + override val options = listOf( + ListPreferenceOption(id = 1, text = "A"), + ListPreferenceOption(id = 2, text = "B"), + ) + override val selectedId = selectedId + override val onIdSelected = { id: Int -> selectedId.intValue = id } + } + }) + } + enabledState.value = false + composeTestRule.onNodeWithText("A").assertIsDisplayed().assertIsNotEnabled() + composeTestRule.onNodeWithText("B").assertIsDisplayed().assertIsNotEnabled() + } + + private companion object { + const val TITLE = "Title" + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt index 988afd70aaed..a395266ba5f9 100644 --- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt +++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt @@ -26,6 +26,7 @@ import android.content.pm.PackageManager import android.content.pm.PackageManager.ApplicationInfoFlags import android.content.pm.ResolveInfo import android.os.SystemProperties +import android.util.Log import com.android.internal.R import com.android.settingslib.spaprivileged.framework.common.userManager import kotlinx.coroutines.async @@ -85,19 +86,24 @@ class AppListRepositoryImpl( userId: Int, loadInstantApps: Boolean, matchAnyUserForAdmin: Boolean, - ): List<ApplicationInfo> = coroutineScope { - val hiddenSystemModulesDeferred = async { packageManager.getHiddenSystemModules() } - val hideWhenDisabledPackagesDeferred = async { - context.resources.getStringArray(R.array.config_hideWhenDisabled_packageNames) - } - val installedApplicationsAsUser = - getInstalledApplications(userId, matchAnyUserForAdmin) + ): List<ApplicationInfo> = try { + coroutineScope { + val hiddenSystemModulesDeferred = async { packageManager.getHiddenSystemModules() } + val hideWhenDisabledPackagesDeferred = async { + context.resources.getStringArray(R.array.config_hideWhenDisabled_packageNames) + } + val installedApplicationsAsUser = + getInstalledApplications(userId, matchAnyUserForAdmin) - val hiddenSystemModules = hiddenSystemModulesDeferred.await() - val hideWhenDisabledPackages = hideWhenDisabledPackagesDeferred.await() - installedApplicationsAsUser.filter { app -> - app.isInAppList(loadInstantApps, hiddenSystemModules, hideWhenDisabledPackages) + val hiddenSystemModules = hiddenSystemModulesDeferred.await() + val hideWhenDisabledPackages = hideWhenDisabledPackagesDeferred.await() + installedApplicationsAsUser.filter { app -> + app.isInAppList(loadInstantApps, hiddenSystemModules, hideWhenDisabledPackages) + } } + } catch (e: Exception) { + Log.e(TAG, "loadApps failed", e) + emptyList() } private suspend fun getInstalledApplications( @@ -210,6 +216,8 @@ class AppListRepositoryImpl( } companion object { + private const val TAG = "AppListRepository" + private fun ApplicationInfo.isInAppList( showInstantApps: Boolean, hiddenSystemModules: Set<String>, diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt index efd53a4c9c23..c60ce41be87e 100644 --- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt +++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt @@ -28,6 +28,8 @@ import android.content.pm.PackageManager.ResolveInfoFlags import android.content.pm.ResolveInfo import android.content.pm.UserInfo import android.content.res.Resources +import android.os.BadParcelableException +import android.os.DeadObjectException import android.os.UserManager import android.platform.test.flag.junit.SetFlagsRule import androidx.test.core.app.ApplicationProvider @@ -44,6 +46,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.doAnswer import org.mockito.kotlin.doReturn +import org.mockito.kotlin.doThrow import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.spy @@ -311,6 +314,19 @@ class AppListRepositoryTest { } @Test + fun loadApps_hasException_returnEmptyList() = runTest { + packageManager.stub { + on { + getInstalledApplicationsAsUser(any<ApplicationInfoFlags>(), eq(ADMIN_USER_ID)) + } doThrow BadParcelableException(DeadObjectException()) + } + + val appList = repository.loadApps(userId = ADMIN_USER_ID) + + assertThat(appList).isEmpty() + } + + @Test fun showSystemPredicate_showSystem() = runTest { val app = SYSTEM_APP diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig index 6a1ee3a3c623..54c5a14702f6 100644 --- a/packages/SettingsLib/aconfig/settingslib.aconfig +++ b/packages/SettingsLib/aconfig/settingslib.aconfig @@ -43,4 +43,11 @@ flag { namespace: "pixel_cross_device_control" description: "Gates whether to enable LE audio private broadcast sharing via QR code" bug: "308368124" -}
\ No newline at end of file +} + +flag { + name: "enable_hide_exclusively_managed_bluetooth_device" + namespace: "dck_framework" + description: "Hide exclusively managed Bluetooth devices in BT settings menu." + bug: "324475542" +} diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar.xml new file mode 100644 index 000000000000..d9a417f1ea99 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar.xml @@ -0,0 +1,37 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="14dp" + android:height="14dp" + android:viewportWidth="14.0" + android:viewportHeight="14.0"> + <path + android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z" + android:fillAlpha="0.24" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml new file mode 100644 index 000000000000..facc285a45ca --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_0_4_bar_error.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="15dp" + android:height="14dp" + android:viewportWidth="15.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z" + android:fillColor="#000"/> + <path + android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar.xml new file mode 100644 index 000000000000..2c05a938c2cf --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar.xml @@ -0,0 +1,41 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="14dp" + android:viewportWidth="16.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z" + android:fillAlpha="0.24" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar_error.xml new file mode 100644 index 000000000000..328e45ec7e19 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_0_5_bar_error.xml @@ -0,0 +1,32 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="14dp" + android:viewportWidth="18.0" + android:viewportHeight="14.0"> + <path + android:pathData="M14,0.5C14,0.224 14.224,0 14.5,0H15.5C15.776,0 16,0.224 16,0.5V3H14V0.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M0.5,11C0.224,11 0,11.224 0,11.5V13.5C0,13.776 0.224,14 0.5,14H1.5C1.776,14 2,13.776 2,13.5V11.5C2,11.224 1.776,11 1.5,11H0.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M4,8C3.724,8 3.5,8.224 3.5,8.5V13.5C3.5,13.776 3.724,14 4,14H5C5.276,14 5.5,13.776 5.5,13.5V8.5C5.5,8.224 5.276,8 5,8H4Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z" + android:fillColor="#000"/> + <path + android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar.xml new file mode 100644 index 000000000000..b9054ba7a4e3 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar.xml @@ -0,0 +1,36 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="14dp" + android:height="14dp" + android:viewportWidth="14.0" + android:viewportHeight="14.0"> + <path + android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z" + android:fillColor="#000"/> + <path + android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z" + android:fillAlpha="0.24" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml new file mode 100644 index 000000000000..03a93491491c --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_1_4_bar_error.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="15dp" + android:height="14dp" + android:viewportWidth="15.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z" + android:fillColor="#000"/> + <path + android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z" + android:fillColor="#000"/> + <path + android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar.xml new file mode 100644 index 000000000000..774e91794df3 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar.xml @@ -0,0 +1,40 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="14dp" + android:viewportWidth="16.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z" + android:fillColor="#000"/> + <path + android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z" + android:fillAlpha="0.24" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar_error.xml new file mode 100644 index 000000000000..343ec1b2e50f --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_1_5_bar_error.xml @@ -0,0 +1,31 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="14dp" + android:viewportWidth="18.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z" + android:fillColor="#000"/> + <path + android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z" + android:fillColor="#000"/> + <path + android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar.xml new file mode 100644 index 000000000000..b699203dd652 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar.xml @@ -0,0 +1,35 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="14dp" + android:height="14dp" + android:viewportWidth="14.0" + android:viewportHeight="14.0"> + <path + android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z" + android:fillColor="#000"/> + <path + android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar_error.xml new file mode 100644 index 000000000000..ba8649b23b38 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_2_4_bar_error.xml @@ -0,0 +1,26 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="15dp" + android:height="14dp" + android:viewportWidth="15.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z" + android:fillColor="#000"/> + <path + android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z" + android:fillColor="#000"/> + <path + android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z" + android:fillColor="#000"/> + <path + android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar.xml new file mode 100644 index 000000000000..43fa734c0c8d --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar.xml @@ -0,0 +1,39 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="14dp" + android:viewportWidth="16.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z" + android:fillColor="#000"/> + <path + android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar_error.xml new file mode 100644 index 000000000000..6309e1772d4a --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_2_5_bar_error.xml @@ -0,0 +1,30 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="14dp" + android:viewportWidth="18.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z" + android:fillColor="#000"/> + <path + android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z" + android:fillColor="#000"/> + <path + android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z" + android:fillColor="#000"/> + <path + android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar.xml new file mode 100644 index 000000000000..6a218b310b3a --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar.xml @@ -0,0 +1,34 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="14dp" + android:height="14dp" + android:viewportWidth="14.0" + android:viewportHeight="14.0"> + <path + android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z" + android:fillColor="#000"/> + <path + android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z" + android:fillColor="#000"/> + <path + android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml new file mode 100644 index 000000000000..27433c79e8bb --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_3_4_bar_error.xml @@ -0,0 +1,25 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="15dp" + android:height="14dp" + android:viewportWidth="15.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z" + android:fillColor="#000"/> + <path + android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z" + android:fillColor="#000"/> + <path + android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z" + android:fillColor="#000"/> + <path + android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z" + android:fillColor="#000"/> + <path + android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar.xml new file mode 100644 index 000000000000..158ae016ffb5 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar.xml @@ -0,0 +1,38 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="14dp" + android:viewportWidth="16.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z" + android:fillColor="#000"/> + <path + android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z" + android:fillColor="#000"/> + <path + android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar_error.xml new file mode 100644 index 000000000000..e0517cfdfeee --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_3_5_bar_error.xml @@ -0,0 +1,29 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="14dp" + android:viewportWidth="18.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z" + android:fillColor="#000"/> + <path + android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z" + android:fillColor="#000"/> + <path + android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z" + android:fillColor="#000"/> + <path + android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z" + android:fillColor="#000"/> + <path + android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar.xml new file mode 100644 index 000000000000..1ebd3965f36f --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar.xml @@ -0,0 +1,33 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="14dp" + android:height="14dp" + android:viewportWidth="14.0" + android:viewportHeight="14.0"> + <path + android:pathData="M8.25,3L9.25,3A0.5,0.5 0,0 1,9.75 3.5L9.75,13.5A0.5,0.5 0,0 1,9.25 14L8.25,14A0.5,0.5 0,0 1,7.75 13.5L7.75,3.5A0.5,0.5 0,0 1,8.25 3z" + android:fillColor="#000"/> + <path + android:pathData="M11.75,0L12.75,0A0.5,0.5 0,0 1,13.25 0.5L13.25,13.5A0.5,0.5 0,0 1,12.75 14L11.75,14A0.5,0.5 0,0 1,11.25 13.5L11.25,0.5A0.5,0.5 0,0 1,11.75 0z" + android:fillColor="#000"/> + <path + android:pathData="M1.25,10L2.25,10A0.5,0.5 0,0 1,2.75 10.5L2.75,13.5A0.5,0.5 0,0 1,2.25 14L1.25,14A0.5,0.5 0,0 1,0.75 13.5L0.75,10.5A0.5,0.5 0,0 1,1.25 10z" + android:fillColor="#000"/> + <path + android:pathData="M4.75,6.5L5.75,6.5A0.5,0.5 0,0 1,6.25 7L6.25,13.5A0.5,0.5 0,0 1,5.75 14L4.75,14A0.5,0.5 0,0 1,4.25 13.5L4.25,7A0.5,0.5 0,0 1,4.75 6.5z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml new file mode 100644 index 000000000000..4473c29d0866 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_4_4_bar_error.xml @@ -0,0 +1,24 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="15dp" + android:height="14dp" + android:viewportWidth="15.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7,3.5C7,3.224 7.224,3 7.5,3H8.5C8.776,3 9,3.224 9,3.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V3.5Z" + android:fillColor="#000"/> + <path + android:pathData="M0,10.5C0,10.224 0.224,10 0.5,10H1.5C1.776,10 2,10.224 2,10.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V10.5Z" + android:fillColor="#000"/> + <path + android:pathData="M3.5,7C3.5,6.724 3.724,6.5 4,6.5H5C5.276,6.5 5.5,6.724 5.5,7V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V7Z" + android:fillColor="#000"/> + <path + android:pathData="M11,0C10.724,0 10.5,0.224 10.5,0.5V3H12.5V0.5C12.5,0.224 12.276,0 12,0H11Z" + android:fillColor="#000"/> + <path + android:pathData="M12.25,13C12.25,12.448 12.698,12 13.25,12C13.802,12 14.25,12.448 14.25,13C14.25,13.552 13.802,14 13.25,14C12.698,14 12.25,13.552 12.25,13Z" + android:fillColor="#000"/> + <path + android:pathData="M12.25,5C12.25,4.724 12.474,4.5 12.75,4.5H13.75C14.026,4.5 14.25,4.724 14.25,5V10C14.25,10.276 14.026,10.5 13.75,10.5H12.75C12.474,10.5 12.25,10.276 12.25,10V5Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar.xml new file mode 100644 index 000000000000..1ed6ac86b21a --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar.xml @@ -0,0 +1,37 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="14dp" + android:viewportWidth="16.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z" + android:fillColor="#000"/> + <path + android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z" + android:fillColor="#000"/> + <path + android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z" + android:fillColor="#000"/> + <path + android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar_error.xml new file mode 100644 index 000000000000..703e3acd5f75 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_4_5_bar_error.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="14dp" + android:viewportWidth="18.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z" + android:fillColor="#000"/> + <path + android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z" + android:fillColor="#000"/> + <path + android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z" + android:fillColor="#000"/> + <path + android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z" + android:fillColor="#000"/> + <path + android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z" + android:fillColor="#000"/> + <path + android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar.xml b/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar.xml new file mode 100644 index 000000000000..420ffb601e8f --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar.xml @@ -0,0 +1,36 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="16dp" + android:height="14dp" + android:viewportWidth="16.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7.5,5L8.5,5A0.5,0.5 0,0 1,9 5.5L9,13.5A0.5,0.5 0,0 1,8.5 14L7.5,14A0.5,0.5 0,0 1,7 13.5L7,5.5A0.5,0.5 0,0 1,7.5 5z" + android:fillColor="#000"/> + <path + android:pathData="M11,2L12,2A0.5,0.5 0,0 1,12.5 2.5L12.5,13.5A0.5,0.5 0,0 1,12 14L11,14A0.5,0.5 0,0 1,10.5 13.5L10.5,2.5A0.5,0.5 0,0 1,11 2z" + android:fillColor="#000"/> + <path + android:pathData="M0.5,11L1.5,11A0.5,0.5 0,0 1,2 11.5L2,13.5A0.5,0.5 0,0 1,1.5 14L0.5,14A0.5,0.5 0,0 1,0 13.5L0,11.5A0.5,0.5 0,0 1,0.5 11z" + android:fillColor="#000"/> + <path + android:pathData="M14.5,0L15.5,0A0.5,0.5 0,0 1,16 0.5L16,13.5A0.5,0.5 0,0 1,15.5 14L14.5,14A0.5,0.5 0,0 1,14 13.5L14,0.5A0.5,0.5 0,0 1,14.5 0z" + android:fillColor="#000"/> + <path + android:pathData="M4,8L5,8A0.5,0.5 0,0 1,5.5 8.5L5.5,13.5A0.5,0.5 0,0 1,5 14L4,14A0.5,0.5 0,0 1,3.5 13.5L3.5,8.5A0.5,0.5 0,0 1,4 8z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar_error.xml b/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar_error.xml new file mode 100644 index 000000000000..e63ca77e9db1 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_5_5_bar_error.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="14dp" + android:viewportWidth="18.0" + android:viewportHeight="14.0"> + <path + android:pathData="M7,5.5C7,5.224 7.224,5 7.5,5H8.5C8.776,5 9,5.224 9,5.5V13.5C9,13.776 8.776,14 8.5,14H7.5C7.224,14 7,13.776 7,13.5V5.5Z" + android:fillColor="#000"/> + <path + android:pathData="M10.5,2.5C10.5,2.224 10.724,2 11,2H12C12.276,2 12.5,2.224 12.5,2.5V13.5C12.5,13.776 12.276,14 12,14H11C10.724,14 10.5,13.776 10.5,13.5V2.5Z" + android:fillColor="#000"/> + <path + android:pathData="M0,11.5C0,11.224 0.224,11 0.5,11H1.5C1.776,11 2,11.224 2,11.5V13.5C2,13.776 1.776,14 1.5,14H0.5C0.224,14 0,13.776 0,13.5V11.5Z" + android:fillColor="#000"/> + <path + android:pathData="M3.5,8.5C3.5,8.224 3.724,8 4,8H5C5.276,8 5.5,8.224 5.5,8.5V13.5C5.5,13.776 5.276,14 5,14H4C3.724,14 3.5,13.776 3.5,13.5V8.5Z" + android:fillColor="#000"/> + <path + android:pathData="M14.5,0C14.224,0 14,0.224 14,0.5V3H16V0.5C16,0.224 15.776,0 15.5,0H14.5Z" + android:fillColor="#000"/> + <path + android:pathData="M16,13C16,12.448 16.448,12 17,12C17.552,12 18,12.448 18,13C18,13.552 17.552,14 17,14C16.448,14 16,13.552 16,13Z" + android:fillColor="#000"/> + <path + android:pathData="M16,5C16,4.724 16.224,4.5 16.5,4.5H17.5C17.776,4.5 18,4.724 18,5V10C18,10.276 17.776,10.5 17.5,10.5H16.5C16.224,10.5 16,10.276 16,10V5Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_mobile_level_list.xml b/packages/SettingsLib/res/drawable/ic_mobile_level_list.xml new file mode 100644 index 000000000000..6ec6793ea233 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_mobile_level_list.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 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 + --> + +<!-- In order to pack the 0-4 and 0-5 ranges into a single element, we use a range offset. See +SignalDrawable.java for usage. --> +<level-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:minLevel="0" android:maxLevel="0" android:drawable="@drawable/ic_mobile_0_4_bar" /> + <item android:minLevel="1" android:maxLevel="1" android:drawable="@drawable/ic_mobile_1_4_bar" /> + <item android:minLevel="2" android:maxLevel="2" android:drawable="@drawable/ic_mobile_2_4_bar" /> + <item android:minLevel="3" android:maxLevel="3" android:drawable="@drawable/ic_mobile_3_4_bar" /> + <item android:minLevel="4" android:maxLevel="4" android:drawable="@drawable/ic_mobile_4_4_bar" /> + <item android:minLevel="10" android:maxLevel="10" android:drawable="@drawable/ic_mobile_0_5_bar" /> + <item android:minLevel="11" android:maxLevel="11" android:drawable="@drawable/ic_mobile_1_5_bar" /> + <item android:minLevel="12" android:maxLevel="12" android:drawable="@drawable/ic_mobile_2_5_bar" /> + <item android:minLevel="13" android:maxLevel="13" android:drawable="@drawable/ic_mobile_3_5_bar" /> + <item android:minLevel="14" android:maxLevel="14" android:drawable="@drawable/ic_mobile_4_5_bar" /> + <item android:minLevel="15" android:maxLevel="15" android:drawable="@drawable/ic_mobile_5_5_bar" /> + + <!-- Error states, so we don't have to draw them manually anymore --> + <item android:minLevel="20" android:maxLevel="20" android:drawable="@drawable/ic_mobile_0_4_bar_error" /> + <item android:minLevel="21" android:maxLevel="21" android:drawable="@drawable/ic_mobile_1_4_bar_error" /> + <item android:minLevel="22" android:maxLevel="22" android:drawable="@drawable/ic_mobile_2_4_bar_error" /> + <item android:minLevel="23" android:maxLevel="23" android:drawable="@drawable/ic_mobile_3_4_bar_error" /> + <item android:minLevel="24" android:maxLevel="24" android:drawable="@drawable/ic_mobile_4_4_bar_error" /> + + <item android:minLevel="30" android:maxLevel="30" android:drawable="@drawable/ic_mobile_0_5_bar_error" /> + <item android:minLevel="31" android:maxLevel="31" android:drawable="@drawable/ic_mobile_1_5_bar_error" /> + <item android:minLevel="32" android:maxLevel="32" android:drawable="@drawable/ic_mobile_2_5_bar_error" /> + <item android:minLevel="33" android:maxLevel="33" android:drawable="@drawable/ic_mobile_3_5_bar_error" /> + <item android:minLevel="34" android:maxLevel="34" android:drawable="@drawable/ic_mobile_4_5_bar_error" /> + <item android:minLevel="35" android:maxLevel="35" android:drawable="@drawable/ic_mobile_5_5_bar_error" /> +</level-list> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_0.xml b/packages/SettingsLib/res/drawable/ic_wifi_0.xml new file mode 100644 index 000000000000..8ff65540c505 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_wifi_0.xml @@ -0,0 +1,37 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="13dp" + android:viewportWidth="18.0" + android:viewportHeight="13.0"> + <path + android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z" + android:fillAlpha="0.24" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_0_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_0_error.xml new file mode 100644 index 000000000000..db31b9dd0fcd --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_wifi_0_error.xml @@ -0,0 +1,28 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="13dp" + android:viewportWidth="17.0" + android:viewportHeight="13.0"> + <path + android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z" + android:fillColor="#000"/> + <path + android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_1.xml b/packages/SettingsLib/res/drawable/ic_wifi_1.xml new file mode 100644 index 000000000000..e170f1dadc94 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_wifi_1.xml @@ -0,0 +1,36 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="13dp" + android:viewportWidth="18.0" + android:viewportHeight="13.0"> + <path + android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_1_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_1_error.xml new file mode 100644 index 000000000000..a4d6a5c00b15 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_wifi_1_error.xml @@ -0,0 +1,27 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="13dp" + android:viewportWidth="17.0" + android:viewportHeight="13.0"> + <path + android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z" + android:fillColor="#000"/> + <path + android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z" + android:fillColor="#000"/> + <path + android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_2.xml b/packages/SettingsLib/res/drawable/ic_wifi_2.xml new file mode 100644 index 000000000000..fc62267ad5b0 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_wifi_2.xml @@ -0,0 +1,35 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="13dp" + android:viewportWidth="18.0" + android:viewportHeight="13.0"> + <path + android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z" + android:fillColor="#000"/> + <path + android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_2_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_2_error.xml new file mode 100644 index 000000000000..65f40eff1ca8 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_wifi_2_error.xml @@ -0,0 +1,26 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="13dp" + android:viewportWidth="17.0" + android:viewportHeight="13.0"> + <path + android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z" + android:fillColor="#000"/> + <path + android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z" + android:fillColor="#000"/> + <path + android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z" + android:fillColor="#000"/> + <path + android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_3.xml b/packages/SettingsLib/res/drawable/ic_wifi_3.xml new file mode 100644 index 000000000000..9079daf922b8 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_wifi_3.xml @@ -0,0 +1,34 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="13dp" + android:viewportWidth="18.0" + android:viewportHeight="13.0"> + <path + android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z" + android:fillAlpha="0.24" + android:fillColor="#000"/> + <path + android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z" + android:fillColor="#000"/> + <path + android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z" + android:fillColor="#000"/> + <path + android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_3_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_3_error.xml new file mode 100644 index 000000000000..940781bbb1ca --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_wifi_3_error.xml @@ -0,0 +1,25 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="13dp" + android:viewportWidth="17.0" + android:viewportHeight="13.0"> + <path + android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z" + android:fillAlpha="0.3" + android:fillColor="#000"/> + <path + android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z" + android:fillColor="#000"/> + <path + android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z" + android:fillColor="#000"/> + <path + android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z" + android:fillColor="#000"/> + <path + android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z" + android:fillColor="#000"/> + <path + android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_4.xml b/packages/SettingsLib/res/drawable/ic_wifi_4.xml new file mode 100644 index 000000000000..6185e4a83332 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_wifi_4.xml @@ -0,0 +1,33 @@ +<!-- + Copyright (C) 2023 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="13dp" + android:viewportWidth="18.0" + android:viewportHeight="13.0"> + <path + android:pathData="M0.523,3.314C0.32,3.502 0.32,3.819 0.516,4.015L1.223,4.722C1.418,4.917 1.734,4.916 1.938,4.73C5.936,1.09 12.066,1.09 16.064,4.73C16.268,4.916 16.584,4.917 16.779,4.722L17.486,4.015C17.682,3.819 17.682,3.502 17.479,3.314C12.698,-1.105 5.304,-1.105 0.523,3.314Z" + android:fillColor="#000"/> + <path + android:pathData="M15.011,6.49C15.207,6.294 15.207,5.976 15.002,5.792C11.592,2.736 6.411,2.736 3,5.792C2.795,5.976 2.795,6.294 2.991,6.49L3.698,7.197C3.893,7.392 4.209,7.39 4.417,7.209C7.042,4.93 10.96,4.93 13.585,7.209C13.793,7.39 14.109,7.392 14.304,7.197L15.011,6.49Z" + android:fillColor="#000"/> + <path + android:pathData="M5.465,8.964C5.27,8.769 5.269,8.45 5.481,8.273C7.515,6.576 10.487,6.576 12.521,8.273C12.733,8.45 12.732,8.769 12.537,8.964L11.83,9.672C11.634,9.867 11.319,9.863 11.099,9.698C9.859,8.767 8.143,8.767 6.904,9.698C6.683,9.863 6.368,9.867 6.173,9.672L5.465,8.964Z" + android:fillColor="#000"/> + <path + android:pathData="M10.062,11.439C10.257,11.244 10.259,10.92 10.022,10.779C9.395,10.407 8.608,10.407 7.98,10.779C7.743,10.92 7.745,11.244 7.94,11.439L8.647,12.146C8.843,12.342 9.159,12.342 9.355,12.146L10.062,11.439Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/drawable/ic_wifi_4_error.xml b/packages/SettingsLib/res/drawable/ic_wifi_4_error.xml new file mode 100644 index 000000000000..715aaa0982e9 --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_wifi_4_error.xml @@ -0,0 +1,24 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="17dp" + android:height="13dp" + android:viewportWidth="17.0" + android:viewportHeight="13.0"> + <path + android:pathData="M0.146,4.015C-0.05,3.819 -0.05,3.502 0.153,3.314C4.002,-0.244 9.545,-0.937 14.055,1.234C13.339,1.449 12.792,2.053 12.66,2.801C8.998,1.281 4.65,1.924 1.568,4.73C1.364,4.916 1.048,4.917 0.853,4.722L0.146,4.015Z" + android:fillColor="#000"/> + <path + android:pathData="M12.63,4.435C9.406,2.836 5.424,3.288 2.63,5.792C2.424,5.976 2.425,6.294 2.621,6.49L3.328,7.197C3.523,7.392 3.839,7.39 4.047,7.209C6.484,5.094 10.033,4.942 12.63,6.753V4.435Z" + android:fillColor="#000"/> + <path + android:pathData="M5.095,8.964C4.9,8.769 4.899,8.45 5.111,8.273C7.145,6.576 10.117,6.576 12.151,8.273C12.363,8.45 12.362,8.769 12.166,8.964L11.459,9.672C11.264,9.867 10.949,9.863 10.728,9.698C9.489,8.767 7.773,8.767 6.533,9.698C6.313,9.863 5.998,9.867 5.802,9.672L5.095,8.964Z" + android:fillColor="#000"/> + <path + android:pathData="M9.652,10.779C9.889,10.92 9.887,11.244 9.692,11.439L8.984,12.146C8.789,12.342 8.473,12.342 8.277,12.146L7.57,11.439C7.375,11.244 7.373,10.92 7.61,10.779C8.237,10.407 9.024,10.407 9.652,10.779Z" + android:fillColor="#000"/> + <path + android:pathData="M14.63,11.15C14.63,10.598 15.078,10.15 15.63,10.15C16.182,10.15 16.63,10.598 16.63,11.15C16.63,11.703 16.182,12.15 15.63,12.15C15.078,12.15 14.63,11.703 14.63,11.15Z" + android:fillColor="#000"/> + <path + android:pathData="M14.63,3.15C14.63,2.874 14.854,2.65 15.13,2.65H16.13C16.406,2.65 16.63,2.874 16.63,3.15V8.15C16.63,8.427 16.406,8.65 16.13,8.65H15.13C14.854,8.65 14.63,8.427 14.63,8.15V3.15Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 9588e502f28e..a4bc235aaa7a 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1085,7 +1085,7 @@ <!-- [CHAR_LIMIT=NONE] Label for charging on hold on main page of settings --> <string name="power_charging_on_hold_settings_home_page"><xliff:g id="level">%1$s</xliff:g> - Charging on hold to protect battery</string> <!-- [CHAR_LIMIT=NONE] Label for incompatible charging accessory on main page of settings --> - <string name="power_incompatible_charging_settings_home_page"><xliff:g id="level">%1$s</xliff:g> - Checking charging accessory</string> + <string name="power_incompatible_charging_settings_home_page"><xliff:g id="level">%1$s</xliff:g> - Check charging accessory</string> <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery discharging --> <string name="power_remaining_duration_only">About <xliff:g id="time_remaining">%1$s</xliff:g> left</string> <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration --> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java index 6ee403d50751..bd27c896a3c4 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java @@ -19,6 +19,7 @@ package com.android.settingslib.bluetooth; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; import android.annotation.CallbackExecutor; +import android.annotation.IntDef; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothCsipSetCoordinator; @@ -35,6 +36,7 @@ import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile.ServiceListener; import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; import android.database.ContentObserver; import android.net.Uri; import android.os.Build; @@ -52,6 +54,8 @@ import com.android.settingslib.R; import com.google.common.collect.ImmutableList; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -71,6 +75,18 @@ import java.util.stream.Collectors; * result callback. */ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { + public static final String ACTION_LE_AUDIO_SHARING_STATE_CHANGE = + "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STATE_CHANGE"; + public static final String EXTRA_LE_AUDIO_SHARING_STATE = "BLUETOOTH_LE_AUDIO_SHARING_STATE"; + public static final int BROADCAST_STATE_UNKNOWN = 0; + public static final int BROADCAST_STATE_ON = 1; + public static final int BROADCAST_STATE_OFF = 2; + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"BROADCAST_STATE_"}, + value = {BROADCAST_STATE_UNKNOWN, BROADCAST_STATE_ON, BROADCAST_STATE_OFF}) + public @interface BroadcastState {} + private static final String SETTINGS_PKG = "com.android.settings"; private static final String TAG = "LocalBluetoothLeBroadcast"; private static final boolean DEBUG = BluetoothUtils.D; @@ -89,7 +105,6 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { Settings.Secure.getUriFor( Settings.Secure.BLUETOOTH_LE_BROADCAST_IMPROVE_COMPATIBILITY), }; - private final Context mContext; private final CachedBluetoothDeviceManager mDeviceManager; private BluetoothLeBroadcast mServiceBroadcast; @@ -200,6 +215,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = " + broadcastId); } setLatestBluetoothLeBroadcastMetadata(metadata); + notifyBroadcastStateChange(BROADCAST_STATE_ON); } @Override @@ -212,7 +228,7 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { + ", broadcastId = " + broadcastId); } - + notifyBroadcastStateChange(BROADCAST_STATE_OFF); stopLocalSourceReceivers(); resetCacheInfo(); } @@ -1005,10 +1021,6 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { /** Update fallback active device if needed. */ public void updateFallbackActiveDeviceIfNeeded() { - if (!isEnabled(null)) { - Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to no ongoing broadcast"); - return; - } if (mServiceBroadcastAssistant == null) { Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to assistant profile is null"); return; @@ -1078,4 +1090,15 @@ public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile { "bluetooth_le_broadcast_fallback_active_group_id", BluetoothCsipSetCoordinator.GROUP_ID_INVALID); } + + private void notifyBroadcastStateChange(@BroadcastState int state) { + if (!mContext.getPackageName().equals(SETTINGS_PKG)) { + Log.d(TAG, "Skip notifyBroadcastStateChange, not triggered by Settings."); + return; + } + Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE); + intent.putExtra(EXTRA_LE_AUDIO_SHARING_STATE, state); + intent.setPackage(mContext.getPackageName()); + mContext.sendBroadcast(intent); + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java index 9a19f9368449..ef0f6cbc6ed9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java +++ b/packages/SettingsLib/src/com/android/settingslib/graph/SignalDrawable.java @@ -14,6 +14,8 @@ package com.android.settingslib.graph; +import static com.android.settingslib.flags.Flags.newStatusBarIcons; + import android.animation.ArgbEvaluator; import android.annotation.IntRange; import android.content.Context; @@ -67,6 +69,9 @@ public class SignalDrawable extends DrawableWrapper { private static final long DOT_DELAY = 1000; + // Check the config for which icon we want to use + private static final int ICON_RES = SignalDrawable.getIconRes(); + private final Paint mForegroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint mTransparentPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final int mDarkModeFillColor; @@ -85,7 +90,7 @@ public class SignalDrawable extends DrawableWrapper { private int mCurrentDot; public SignalDrawable(Context context) { - super(context.getDrawable(com.android.internal.R.drawable.ic_signal_cellular)); + super(context.getDrawable(ICON_RES)); final String attributionPathString = context.getString( com.android.internal.R.string.config_signalAttributionPath); mAttributionPath.set(PathParser.createPathFromPathData(attributionPathString)); @@ -147,9 +152,17 @@ public class SignalDrawable extends DrawableWrapper { private int unpackLevel(int packedState) { int numBins = (packedState & NUM_LEVEL_MASK) >> NUM_LEVEL_SHIFT; + int cutOutOffset = 0; int levelOffset = numBins == (CellSignalStrength.getNumSignalStrengthLevels() + 1) ? 10 : 0; int level = (packedState & LEVEL_MASK); - return level + levelOffset; + + if (newStatusBarIcons()) { + if (isInState(STATE_CUT)) { + cutOutOffset = 20; + } + } + + return level + levelOffset + cutOutOffset; } public void setDarkIntensity(float darkIntensity) { @@ -214,7 +227,7 @@ public class SignalDrawable extends DrawableWrapper { drawDotAndPadding(x - dotSpacing * 2, y, dotPadding, dotSize, 0); canvas.drawPath(mCutoutPath, mTransparentPaint); canvas.drawPath(mForegroundPath, mForegroundPaint); - } else if (isInState(STATE_CUT)) { + } else if (!newStatusBarIcons() && isInState(STATE_CUT)) { float cutX = (mCutoutWidthFraction * width / VIEWPORT); float cutY = (mCutoutHeightFraction * height / VIEWPORT); mCutoutPath.moveTo(width, height); @@ -300,4 +313,12 @@ public class SignalDrawable extends DrawableWrapper { public static int getCarrierChangeState(int numLevels) { return (STATE_CARRIER_CHANGE << STATE_SHIFT) | (numLevels << NUM_LEVEL_SHIFT); } + + private static int getIconRes() { + if (newStatusBarIcons()) { + return R.drawable.ic_mobile_level_list; + } else { + return com.android.internal.R.drawable.ic_signal_cellular; + } + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index 50e2f9cb13f7..bdb58719b1a8 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -139,7 +139,6 @@ public abstract class InfoMediaManager extends MediaManager { } } - @Override public void startScan() { mMediaDevices.clear(); startScanOnRouter(); @@ -156,7 +155,6 @@ public abstract class InfoMediaManager extends MediaManager { } } - @Override public abstract void stopScan(); protected abstract void startScanOnRouter(); diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java index dfbf23f426fb..8bebd6ee3448 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java @@ -54,16 +54,6 @@ public abstract class MediaManager { } } - /** - * Start scan connected MediaDevice - */ - public abstract void startScan(); - - /** - * Stop scan MediaDevice - */ - public abstract void stopScan(); - protected MediaDevice findMediaDevice(String id) { for (MediaDevice mediaDevice : mMediaDevices) { if (mediaDevice.getId().equals(id)) { diff --git a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java index 0f08605a50d0..df03167cd0f9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java @@ -41,6 +41,7 @@ import java.util.HashMap; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -64,6 +65,8 @@ public final class RouterInfoMediaManager extends InfoMediaManager { refreshDevices(); }; + private final AtomicReference<MediaRouter2.ScanToken> mScanToken = new AtomicReference<>(); + // TODO (b/321969740): Plumb target UserHandle between UMO and RouterInfoMediaManager. /* package */ RouterInfoMediaManager( Context context, @@ -101,12 +104,24 @@ public final class RouterInfoMediaManager extends InfoMediaManager { mExecutor, mRouteListingPreferenceCallback); mRouter.registerTransferCallback(mExecutor, mTransferCallback); mRouter.registerControllerCallback(mExecutor, mControllerCallback); - mRouter.startScan(); + if (Flags.enableScreenOffScanning()) { + MediaRouter2.ScanRequest request = new MediaRouter2.ScanRequest.Builder().build(); + mScanToken.compareAndSet(null, mRouter.requestScan(request)); + } else { + mRouter.startScan(); + } } @Override public void stopScan() { - mRouter.stopScan(); + if (Flags.enableScreenOffScanning()) { + MediaRouter2.ScanToken token = mScanToken.getAndSet(null); + if (token != null) { + mRouter.cancelScanRequest(token); + } + } else { + mRouter.stopScan(); + } mRouter.unregisterControllerCallback(mControllerCallback); mRouter.unregisterTransferCallback(mTransferCallback); mRouter.unregisterRouteListingPreferenceUpdatedCallback(mRouteListingPreferenceCallback); diff --git a/packages/SettingsLib/src/com/android/settingslib/media/data/repository/SpatializerRepository.kt b/packages/SettingsLib/src/com/android/settingslib/media/data/repository/SpatializerRepository.kt index 2a4658bc69a1..a5c63be3c987 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/data/repository/SpatializerRepository.kt +++ b/packages/SettingsLib/src/com/android/settingslib/media/data/repository/SpatializerRepository.kt @@ -18,33 +18,71 @@ package com.android.settingslib.media.data.repository import android.media.AudioDeviceAttributes import android.media.Spatializer +import androidx.concurrent.futures.DirectExecutor import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch import kotlinx.coroutines.withContext interface SpatializerRepository { + /** Returns true when head tracking is enabled and false the otherwise. */ + val isHeadTrackingAvailable: StateFlow<Boolean> + /** * Returns true when Spatial audio feature is supported for the [audioDeviceAttributes] and * false the otherwise. */ - suspend fun isAvailableForDevice(audioDeviceAttributes: AudioDeviceAttributes): Boolean + suspend fun isSpatialAudioAvailableForDevice( + audioDeviceAttributes: AudioDeviceAttributes + ): Boolean /** Returns a list [AudioDeviceAttributes] that are compatible with spatial audio. */ - suspend fun getCompatibleDevices(): Collection<AudioDeviceAttributes> + suspend fun getSpatialAudioCompatibleDevices(): Collection<AudioDeviceAttributes> + + /** Adds a [audioDeviceAttributes] to [getSpatialAudioCompatibleDevices] list. */ + suspend fun addSpatialAudioCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) + + /** Removes a [audioDeviceAttributes] from [getSpatialAudioCompatibleDevices] list. */ + suspend fun removeSpatialAudioCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) - /** Adds a [audioDeviceAttributes] to [getCompatibleDevices] list. */ - suspend fun addCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) + /** Checks if the head tracking is enabled for the [audioDeviceAttributes]. */ + suspend fun isHeadTrackingEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean - /** Removes a [audioDeviceAttributes] to [getCompatibleDevices] list. */ - suspend fun removeCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) + /** Sets head tracking [isEnabled] for the [audioDeviceAttributes]. */ + suspend fun setHeadTrackingEnabled( + audioDeviceAttributes: AudioDeviceAttributes, + isEnabled: Boolean, + ) } class SpatializerRepositoryImpl( private val spatializer: Spatializer, + coroutineScope: CoroutineScope, private val backgroundContext: CoroutineContext, ) : SpatializerRepository { - override suspend fun isAvailableForDevice( + override val isHeadTrackingAvailable: StateFlow<Boolean> = + callbackFlow { + val listener = + Spatializer.OnHeadTrackerAvailableListener { _, available -> + launch { send(available) } + } + spatializer.addOnHeadTrackerAvailableListener(DirectExecutor.INSTANCE, listener) + awaitClose { spatializer.removeOnHeadTrackerAvailableListener(listener) } + } + .onStart { emit(spatializer.isHeadTrackerAvailable) } + .flowOn(backgroundContext) + .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), false) + + override suspend fun isSpatialAudioAvailableForDevice( audioDeviceAttributes: AudioDeviceAttributes ): Boolean { return withContext(backgroundContext) { @@ -52,18 +90,36 @@ class SpatializerRepositoryImpl( } } - override suspend fun getCompatibleDevices(): Collection<AudioDeviceAttributes> = + override suspend fun getSpatialAudioCompatibleDevices(): Collection<AudioDeviceAttributes> = withContext(backgroundContext) { spatializer.compatibleAudioDevices } - override suspend fun addCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) { + override suspend fun addSpatialAudioCompatibleDevice( + audioDeviceAttributes: AudioDeviceAttributes + ) { withContext(backgroundContext) { spatializer.addCompatibleAudioDevice(audioDeviceAttributes) } } - override suspend fun removeCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) { + override suspend fun removeSpatialAudioCompatibleDevice( + audioDeviceAttributes: AudioDeviceAttributes + ) { withContext(backgroundContext) { spatializer.removeCompatibleAudioDevice(audioDeviceAttributes) } } + + override suspend fun isHeadTrackingEnabled( + audioDeviceAttributes: AudioDeviceAttributes + ): Boolean = + withContext(backgroundContext) { spatializer.isHeadTrackerEnabled(audioDeviceAttributes) } + + override suspend fun setHeadTrackingEnabled( + audioDeviceAttributes: AudioDeviceAttributes, + isEnabled: Boolean, + ) { + withContext(backgroundContext) { + spatializer.setHeadTrackerEnabled(isEnabled, audioDeviceAttributes) + } + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/domain/interactor/SpatializerInteractor.kt b/packages/SettingsLib/src/com/android/settingslib/media/domain/interactor/SpatializerInteractor.kt index c3cc340d9cd8..0347403cb385 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/domain/interactor/SpatializerInteractor.kt +++ b/packages/SettingsLib/src/com/android/settingslib/media/domain/interactor/SpatializerInteractor.kt @@ -18,22 +18,40 @@ package com.android.settingslib.media.domain.interactor import android.media.AudioDeviceAttributes import com.android.settingslib.media.data.repository.SpatializerRepository +import kotlinx.coroutines.flow.StateFlow class SpatializerInteractor(private val repository: SpatializerRepository) { - suspend fun isAvailable(audioDeviceAttributes: AudioDeviceAttributes): Boolean = - repository.isAvailableForDevice(audioDeviceAttributes) + /** Checks if head tracking is available. */ + val isHeadTrackingAvailable: StateFlow<Boolean> + get() = repository.isHeadTrackingAvailable + + suspend fun isSpatialAudioAvailable(audioDeviceAttributes: AudioDeviceAttributes): Boolean = + repository.isSpatialAudioAvailableForDevice(audioDeviceAttributes) /** Checks if spatial audio is enabled for the [audioDeviceAttributes]. */ - suspend fun isEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean = - repository.getCompatibleDevices().contains(audioDeviceAttributes) + suspend fun isSpatialAudioEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean = + repository.getSpatialAudioCompatibleDevices().contains(audioDeviceAttributes) - /** Enblaes or disables spatial audio for [audioDeviceAttributes]. */ - suspend fun setEnabled(audioDeviceAttributes: AudioDeviceAttributes, isEnabled: Boolean) { + /** Enables or disables spatial audio for [audioDeviceAttributes]. */ + suspend fun setSpatialAudioEnabled( + audioDeviceAttributes: AudioDeviceAttributes, + isEnabled: Boolean + ) { if (isEnabled) { - repository.addCompatibleDevice(audioDeviceAttributes) + repository.addSpatialAudioCompatibleDevice(audioDeviceAttributes) } else { - repository.removeCompatibleDevice(audioDeviceAttributes) + repository.removeSpatialAudioCompatibleDevice(audioDeviceAttributes) } } + + /** Checks if head tracking is enabled for the [audioDeviceAttributes]. */ + suspend fun isHeadTrackingEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean = + repository.isHeadTrackingEnabled(audioDeviceAttributes) + + /** Enables or disables head tracking for the [audioDeviceAttributes]. */ + suspend fun setHeadTrackingEnabled( + audioDeviceAttributes: AudioDeviceAttributes, + isEnabled: Boolean, + ) = repository.setHeadTrackingEnabled(audioDeviceAttributes, isEnabled) } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java index b9a464752824..69f83a4dfa3c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java @@ -19,6 +19,8 @@ package com.android.settingslib.wifi; import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED; import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.getMaxNetworkSelectionDisableReason; +import static com.android.settingslib.flags.Flags.newStatusBarIcons; + import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; @@ -88,21 +90,49 @@ public class WifiUtils { public static final String KEY_CHOSEN_WIFIENTRY_KEY = "key_chosen_wifientry_key"; public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"; - static final int[] WIFI_PIE = { - com.android.internal.R.drawable.ic_wifi_signal_0, - com.android.internal.R.drawable.ic_wifi_signal_1, - com.android.internal.R.drawable.ic_wifi_signal_2, - com.android.internal.R.drawable.ic_wifi_signal_3, - com.android.internal.R.drawable.ic_wifi_signal_4 - }; - - static final int[] NO_INTERNET_WIFI_PIE = { - R.drawable.ic_no_internet_wifi_signal_0, - R.drawable.ic_no_internet_wifi_signal_1, - R.drawable.ic_no_internet_wifi_signal_2, - R.drawable.ic_no_internet_wifi_signal_3, - R.drawable.ic_no_internet_wifi_signal_4 - }; + static final int[] WIFI_PIE = getIconsBasedOnFlag(); + + private static int[] getIconsBasedOnFlag() { + if (newStatusBarIcons()) { + return new int[] { + R.drawable.ic_wifi_0, + R.drawable.ic_wifi_1, + R.drawable.ic_wifi_2, + R.drawable.ic_wifi_3, + R.drawable.ic_wifi_4 + }; + } else { + return new int[] { + com.android.internal.R.drawable.ic_wifi_signal_0, + com.android.internal.R.drawable.ic_wifi_signal_1, + com.android.internal.R.drawable.ic_wifi_signal_2, + com.android.internal.R.drawable.ic_wifi_signal_3, + com.android.internal.R.drawable.ic_wifi_signal_4 + }; + } + } + + static final int[] NO_INTERNET_WIFI_PIE = getErrorIconsBasedOnFlag(); + + private static int [] getErrorIconsBasedOnFlag() { + if (newStatusBarIcons()) { + return new int[] { + R.drawable.ic_wifi_0_error, + R.drawable.ic_wifi_1_error, + R.drawable.ic_wifi_2_error, + R.drawable.ic_wifi_3_error, + R.drawable.ic_wifi_4_error + }; + } else { + return new int[] { + R.drawable.ic_no_internet_wifi_signal_0, + R.drawable.ic_no_internet_wifi_signal_1, + R.drawable.ic_no_internet_wifi_signal_2, + R.drawable.ic_no_internet_wifi_signal_3, + R.drawable.ic_no_internet_wifi_signal_4 + }; + } + } public static String buildLoggingSummary(AccessPoint accessPoint, WifiConfiguration config) { final StringBuilder summary = new StringBuilder(); diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/FakeSpatializerRepository.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/FakeSpatializerRepository.kt deleted file mode 100644 index 3f52f2494dfc..000000000000 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/FakeSpatializerRepository.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settingslib.media.domain.interactor - -import android.media.AudioDeviceAttributes -import com.android.settingslib.media.data.repository.SpatializerRepository - -class FakeSpatializerRepository : SpatializerRepository { - - private val availabilityByDevice: MutableMap<AudioDeviceAttributes, Boolean> = mutableMapOf() - private val compatibleDevices: MutableList<AudioDeviceAttributes> = mutableListOf() - - override suspend fun isAvailableForDevice( - audioDeviceAttributes: AudioDeviceAttributes - ): Boolean = availabilityByDevice.getOrDefault(audioDeviceAttributes, false) - - override suspend fun getCompatibleDevices(): Collection<AudioDeviceAttributes> = - compatibleDevices - - override suspend fun addCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) { - compatibleDevices.add(audioDeviceAttributes) - } - - override suspend fun removeCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) { - compatibleDevices.remove(audioDeviceAttributes) - } - - fun setIsAvailable(audioDeviceAttributes: AudioDeviceAttributes, isAvailable: Boolean) { - availabilityByDevice[audioDeviceAttributes] = isAvailable - } -} diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/SpatializerInteractorTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/SpatializerInteractorTest.kt deleted file mode 100644 index a44baeb174bf..000000000000 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/SpatializerInteractorTest.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settingslib.media.domain.interactor - -import android.media.AudioDeviceAttributes -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.runTest -import org.junit.Test -import org.junit.runner.RunWith - -@SmallTest -@RunWith(AndroidJUnit4::class) -class SpatializerInteractorTest { - - private val testScope = TestScope() - private val underTest = SpatializerInteractor(FakeSpatializerRepository()) - - @Test - fun setEnabledFalse_isEnabled_false() { - testScope.runTest { - underTest.setEnabled(deviceAttributes, false) - - assertThat(underTest.isEnabled(deviceAttributes)).isFalse() - } - } - - @Test - fun setEnabledTrue_isEnabled_true() { - testScope.runTest { - underTest.setEnabled(deviceAttributes, true) - - assertThat(underTest.isEnabled(deviceAttributes)).isTrue() - } - } - - private companion object { - val deviceAttributes = AudioDeviceAttributes(0, 0, "test_device") - } -} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java index 37052673eb4d..70ba415abde5 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java @@ -20,9 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; import android.annotation.SuppressLint; import android.content.Context; @@ -94,19 +92,6 @@ public class WifiMacAddressPreferenceControllerTest { } @Test - public void updateConnectivity_notAvailable_notCalled() { - boolean mCalled = false; - mController = spy(new ConcreteWifiMacAddressPreferenceController(mContext, mLifecycle) { - @Override - public boolean isAvailable() { - return false; - } - }); - mController.displayPreference(mScreen); - verify(mController, never()).updateConnectivity(); - } - - @Test public void updateConnectivity_null_setMacUnavailable() { doReturn(null).when(mWifiManager).getFactoryMacAddresses(); mController.displayPreference(mScreen); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java index 3b731921f201..46e724d245f5 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java @@ -52,17 +52,7 @@ public class MediaManagerTest { when(mDevice.getId()).thenReturn(TEST_ID); - mMediaManager = new MediaManager(mContext, null) { - @Override - public void startScan() { - - } - - @Override - public void stopScan() { - - } - }; + mMediaManager = new MediaManager(mContext, null) {}; } @Test diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp index d5814e3a9b79..94ea01607714 100644 --- a/packages/SettingsProvider/Android.bp +++ b/packages/SettingsProvider/Android.bp @@ -60,6 +60,7 @@ android_test { // because this test is not an instrumentation test. (because the target runs in the system process.) "SettingsProviderLib", "androidx.test.rules", + "device_config_service_flags_java", "flag-junit", "junit", "libaconfig_java_proto_lite", diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index e424797c664e..2fa1c6eda458 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -227,6 +227,7 @@ public class SecureSettings { Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED, Settings.Secure.ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED, + Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED, Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, Settings.Secure.NOTIFICATION_BUBBLES, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index a32eeadc2982..2535fdb6e4d0 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -321,6 +321,7 @@ public class SecureSettingsValidators { Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put( Secure.ACCESSIBILITY_BUTTON_TARGETS, ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index d27ff175ca25..02d212cb4996 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1865,6 +1865,10 @@ class SettingsProtoDumpUtil { SecureSettingsProto.Accessibility .ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED); dumpSetting(s, p, + Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED, + SecureSettingsProto.Accessibility + .ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED); + dumpSetting(s, p, Settings.Secure.HEARING_AID_RINGTONE_ROUTING, SecureSettingsProto.Accessibility.HEARING_AID_RINGTONE_ROUTING); dumpSetting(s, p, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 1c9e748c5f3a..ce0257f6c85b 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -359,6 +359,15 @@ final class SettingsState { @VisibleForTesting @GuardedBy("mLock") + public void addAconfigDefaultValuesFromMap( + @NonNull Map<String, Map<String, String>> defaultMap) { + if (mNamespaceDefaults != null) { + mNamespaceDefaults.putAll(defaultMap); + } + } + + @VisibleForTesting + @GuardedBy("mLock") public static void loadAconfigDefaultValues(byte[] fileContents, @NonNull Map<String, Map<String, String>> defaultMap) { try { @@ -510,6 +519,28 @@ final class SettingsState { return false; } + // Aconfig flags are always boot stable, so we anytime we write one, we staged it to be + // applied on reboot. + if (Flags.stageAllAconfigFlags() && mNamespaceDefaults != null) { + int slashIndex = name.indexOf("/"); + boolean stageFlag = isConfigSettingsKey(mKey) + && slashIndex != -1 + && slashIndex != 0 + && slashIndex != name.length(); + + if (stageFlag) { + String namespace = name.substring(0, slashIndex); + String flag = name.substring(slashIndex + 1); + + boolean isAconfig = mNamespaceDefaults.containsKey(namespace) + && mNamespaceDefaults.get(namespace).containsKey(name); + + if (isAconfig) { + name = "staged/" + namespace + "*" + flag; + } + } + } + final boolean isNameTooLong = name.length() > SettingsState.MAX_LENGTH_PER_STRING; final boolean isValueTooLong = value != null && value.length() > SettingsState.MAX_LENGTH_PER_STRING; diff --git a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig index ecac5ee18582..e5086e87173a 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig +++ b/packages/SettingsProvider/src/com/android/providers/settings/device_config_service.aconfig @@ -14,3 +14,14 @@ flag { bug: "311155098" is_fixed_read_only: true } + +flag { + name: "stage_all_aconfig_flags" + namespace: "core_experiments_team_internal" + description: "Stage _all_ aconfig flags on writes, even local ones." + bug: "326598713" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java index 9ecbd50fc566..ea30c69b1c45 100644 --- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java +++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java @@ -15,13 +15,25 @@ */ package com.android.providers.settings; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; + import android.aconfig.Aconfig; import android.aconfig.Aconfig.parsed_flag; import android.aconfig.Aconfig.parsed_flags; import android.os.Looper; -import android.test.AndroidTestCase; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.Xml; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + import com.android.modules.utils.TypedXmlSerializer; import com.google.common.base.Strings; @@ -34,7 +46,18 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -public class SettingsStateTest extends AndroidTestCase { +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class SettingsStateTest { + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); + public static final String CRAZY_STRING = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000b\u000c\r" + "\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a" + @@ -76,25 +99,25 @@ public class SettingsStateTest extends AndroidTestCase { private File mSettingsFile; - @Override - protected void setUp() { - mSettingsFile = new File(getContext().getCacheDir(), "setting.xml"); + @Before + public void setUp() { + mSettingsFile = new File(InstrumentationRegistry.getContext().getCacheDir(), "setting.xml"); mSettingsFile.delete(); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { if (mSettingsFile != null) { mSettingsFile.delete(); } - super.tearDown(); } + @Test public void testLoadValidAconfigProto() { int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); Object lock = new Object(); SettingsState settingsState = new SettingsState( - getContext(), lock, mSettingsFile, configKey, + InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); parsed_flags flags = parsed_flags .newBuilder() @@ -129,11 +152,12 @@ public class SettingsStateTest extends AndroidTestCase { } } + @Test public void testSkipLoadingAconfigFlagWithMissingFields() { int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); Object lock = new Object(); SettingsState settingsState = new SettingsState( - getContext(), lock, mSettingsFile, configKey, + InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); parsed_flags flags = parsed_flags @@ -155,12 +179,97 @@ public class SettingsStateTest extends AndroidTestCase { } } + @Test + @RequiresFlagsEnabled(Flags.FLAG_STAGE_ALL_ACONFIG_FLAGS) + public void testWritingAconfigFlagStages() { + int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); + Object lock = new Object(); + SettingsState settingsState = new SettingsState( + InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + parsed_flags flags = parsed_flags + .newBuilder() + .addParsedFlag(parsed_flag + .newBuilder() + .setPackage("com.android.flags") + .setName("flag5") + .setNamespace("test_namespace") + .setDescription("test flag") + .addBug("12345678") + .setState(Aconfig.flag_state.DISABLED) + .setPermission(Aconfig.flag_permission.READ_WRITE)) + .build(); + + synchronized (lock) { + Map<String, Map<String, String>> defaults = new HashMap<>(); + settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); + settingsState.addAconfigDefaultValuesFromMap(defaults); + + settingsState.insertSettingLocked("test_namespace/com.android.flags.flag5", + "true", null, false, "com.android.flags"); + settingsState.insertSettingLocked("test_namespace/com.android.flags.flag6", + "true", null, false, "com.android.flags"); + + assertEquals("true", + settingsState + .getSettingLocked("staged/test_namespace*com.android.flags.flag5") + .getValue()); + assertEquals(null, + settingsState + .getSettingLocked("test_namespace/com.android.flags.flag5") + .getValue()); + + assertEquals(null, + settingsState + .getSettingLocked("staged/test_namespace*com.android.flags.flag6") + .getValue()); + assertEquals("true", + settingsState + .getSettingLocked("test_namespace/com.android.flags.flag6") + .getValue()); + } + } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_LOAD_ACONFIG_DEFAULTS) + public void testAddingAconfigMapOnNullIsNoOp() { + int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); + Object lock = new Object(); + SettingsState settingsState = new SettingsState( + InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + + parsed_flags flags = parsed_flags + .newBuilder() + .addParsedFlag(parsed_flag + .newBuilder() + .setPackage("com.android.flags") + .setName("flag5") + .setNamespace("test_namespace") + .setDescription("test flag") + .addBug("12345678") + .setState(Aconfig.flag_state.DISABLED) + .setPermission(Aconfig.flag_permission.READ_WRITE)) + .build(); + + synchronized (lock) { + Map<String, Map<String, String>> defaults = new HashMap<>(); + settingsState.loadAconfigDefaultValues(flags.toByteArray(), defaults); + settingsState.addAconfigDefaultValuesFromMap(defaults); + + assertEquals(null, settingsState.getAconfigDefaultValues()); + } + + } + + @Test public void testInvalidAconfigProtoDoesNotCrash() { Map<String, Map<String, String>> defaults = new HashMap<>(); SettingsState settingsState = getSettingStateObject(); settingsState.loadAconfigDefaultValues("invalid protobuf".getBytes(), defaults); } + @Test public void testIsBinary() { assertFalse(SettingsState.isBinary(" abc 日本語")); @@ -191,6 +300,7 @@ public class SettingsStateTest extends AndroidTestCase { } /** Make sure we won't pass invalid characters to XML serializer. */ + @Test public void testWriteReadNoCrash() throws Exception { ByteArrayOutputStream os = new ByteArrayOutputStream(); @@ -233,12 +343,15 @@ public class SettingsStateTest extends AndroidTestCase { /** * Make sure settings can be written to a file and also can be read. */ + @Test public void testReadWrite() { final Object lock = new Object(); assertFalse(mSettingsFile.exists()); - final SettingsState ssWriter = new SettingsState(getContext(), lock, mSettingsFile, 1, - SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + final SettingsState ssWriter = + new SettingsState( + InstrumentationRegistry.getContext(), lock, mSettingsFile, 1, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); ssWriter.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING); ssWriter.insertSettingLocked("k1", "\u0000", null, false, "package"); @@ -250,8 +363,10 @@ public class SettingsStateTest extends AndroidTestCase { } ssWriter.waitForHandler(); assertTrue(mSettingsFile.exists()); - final SettingsState ssReader = new SettingsState(getContext(), lock, mSettingsFile, 1, - SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + final SettingsState ssReader = + new SettingsState( + InstrumentationRegistry.getContext(), lock, mSettingsFile, 1, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); synchronized (lock) { assertEquals("\u0000", ssReader.getSettingLocked("k1").getValue()); @@ -264,6 +379,7 @@ public class SettingsStateTest extends AndroidTestCase { /** * In version 120, value "null" meant {code NULL}. */ + @Test public void testUpgrade() throws Exception { final Object lock = new Object(); final PrintStream os = new PrintStream(new FileOutputStream(mSettingsFile)); @@ -276,8 +392,10 @@ public class SettingsStateTest extends AndroidTestCase { "</settings>"); os.close(); - final SettingsState ss = new SettingsState(getContext(), lock, mSettingsFile, 1, - SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + final SettingsState ss = + new SettingsState( + InstrumentationRegistry.getContext(), lock, mSettingsFile, 1, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); synchronized (lock) { SettingsState.Setting s; s = ss.getSettingLocked("k0"); @@ -294,6 +412,7 @@ public class SettingsStateTest extends AndroidTestCase { } } + @Test public void testInitializeSetting_preserveFlagNotSet() { SettingsState settingsWriter = getSettingStateObject(); settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); @@ -304,6 +423,7 @@ public class SettingsStateTest extends AndroidTestCase { assertFalse(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); } + @Test public void testModifySetting_preserveFlagSet() { SettingsState settingsWriter = getSettingStateObject(); settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); @@ -315,6 +435,7 @@ public class SettingsStateTest extends AndroidTestCase { assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); } + @Test public void testModifySettingOverrideableByRestore_preserveFlagNotSet() { SettingsState settingsWriter = getSettingStateObject(); settingsWriter.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE); @@ -327,6 +448,7 @@ public class SettingsStateTest extends AndroidTestCase { assertFalse(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); } + @Test public void testModifySettingOverrideableByRestore_preserveFlagAlreadySet_flagValueUnchanged() { SettingsState settingsWriter = getSettingStateObject(); // Init the setting. @@ -344,6 +466,7 @@ public class SettingsStateTest extends AndroidTestCase { assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); } + @Test public void testResetSetting_preservedFlagIsReset() { SettingsState settingsState = getSettingStateObject(); // Initialize the setting. @@ -356,6 +479,7 @@ public class SettingsStateTest extends AndroidTestCase { } + @Test public void testModifySettingBySystemPackage_sameValue_preserveFlagNotSet() { SettingsState settingsState = getSettingStateObject(); // Initialize the setting. @@ -366,6 +490,7 @@ public class SettingsStateTest extends AndroidTestCase { assertFalse(settingsState.getSettingLocked(SETTING_NAME).isValuePreservedInRestore()); } + @Test public void testModifySettingBySystemPackage_newValue_preserveFlagSet() { SettingsState settingsState = getSettingStateObject(); // Initialize the setting. @@ -377,12 +502,15 @@ public class SettingsStateTest extends AndroidTestCase { } private SettingsState getSettingStateObject() { - SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1, - SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + SettingsState settingsState = + new SettingsState( + InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); settingsState.setVersionLocked(SettingsState.SETTINGS_VERSION_NEW_ENCODING); return settingsState; } + @Test public void testInsertSetting_memoryUsage() { SettingsState settingsState = getSettingStateObject(); // No exception should be thrown when there is no cap @@ -390,8 +518,10 @@ public class SettingsStateTest extends AndroidTestCase { null, false, "p1"); settingsState.deleteSettingLocked(SETTING_NAME); - settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1, - SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper()); + settingsState = + new SettingsState( + InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper()); // System package doesn't have memory usage limit settingsState.insertSettingLocked(SETTING_NAME, Strings.repeat("A", 20001), null, false, SYSTEM_PACKAGE); @@ -425,9 +555,12 @@ public class SettingsStateTest extends AndroidTestCase { } } + @Test public void testMemoryUsagePerPackage() { - SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1, - SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper()); + SettingsState settingsState = + new SettingsState( + InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper()); // Test inserting one key with default final String testKey1 = SETTING_NAME; @@ -512,9 +645,12 @@ public class SettingsStateTest extends AndroidTestCase { assertEquals(expectedMemUsage, settingsState.getMemoryUsage(TEST_PACKAGE)); } + @Test public void testLargeSettingKey() { - SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1, - SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper()); + SettingsState settingsState = + new SettingsState( + InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_LIMITED, Looper.getMainLooper()); final String largeKey = Strings.repeat("A", SettingsState.MAX_LENGTH_PER_STRING + 1); final String testValue = "testValue"; synchronized (mLock) { @@ -535,9 +671,12 @@ public class SettingsStateTest extends AndroidTestCase { } } + @Test public void testLargeSettingValue() { - SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1, - SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); + SettingsState settingsState = + new SettingsState( + InstrumentationRegistry.getContext(), mLock, mSettingsFile, 1, + SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); final String testKey = "testKey"; final String largeValue = Strings.repeat("A", SettingsState.MAX_LENGTH_PER_STRING + 1); synchronized (mLock) { @@ -558,11 +697,12 @@ public class SettingsStateTest extends AndroidTestCase { } } + @Test public void testApplyStagedConfigValues() { int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); Object lock = new Object(); SettingsState settingsState = new SettingsState( - getContext(), lock, mSettingsFile, configKey, + InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); synchronized (lock) { @@ -578,7 +718,8 @@ public class SettingsStateTest extends AndroidTestCase { assertEquals(VALUE2, settingsState.getSettingLocked(FLAG_NAME_2).getValue()); } - settingsState = new SettingsState(getContext(), lock, mSettingsFile, configKey, + settingsState = new SettingsState( + InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); synchronized (lock) { @@ -589,6 +730,7 @@ public class SettingsStateTest extends AndroidTestCase { } } + @Test public void testStagingTransformation() { assertEquals(INVALID_STAGED_FLAG_1, SettingsState.createRealFlagName(INVALID_STAGED_FLAG_1)); @@ -603,11 +745,12 @@ public class SettingsStateTest extends AndroidTestCase { SettingsState.createRealFlagName(VALID_STAGED_FLAG_1)); } + @Test public void testInvalidStagedFlagsUnaffectedByReboot() { int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); Object lock = new Object(); SettingsState settingsState = new SettingsState( - getContext(), lock, mSettingsFile, configKey, + InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); synchronized (lock) { @@ -620,7 +763,8 @@ public class SettingsStateTest extends AndroidTestCase { assertEquals(VALUE2, settingsState.getSettingLocked(INVALID_STAGED_FLAG_1).getValue()); } - settingsState = new SettingsState(getContext(), lock, mSettingsFile, configKey, + settingsState = new SettingsState( + InstrumentationRegistry.getContext(), lock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); synchronized (lock) { @@ -628,6 +772,7 @@ public class SettingsStateTest extends AndroidTestCase { } } + @Test public void testsetSettingsLockedKeepTrunkDefault() throws Exception { final PrintStream os = new PrintStream(new FileOutputStream(mSettingsFile)); os.print( @@ -648,7 +793,7 @@ public class SettingsStateTest extends AndroidTestCase { int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); SettingsState settingsState = new SettingsState( - getContext(), mLock, mSettingsFile, configKey, + InstrumentationRegistry.getContext(), mLock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); String prefix = "test_namespace"; @@ -705,6 +850,7 @@ public class SettingsStateTest extends AndroidTestCase { } } + @Test public void testsetSettingsLockedNoTrunkDefault() throws Exception { final PrintStream os = new PrintStream(new FileOutputStream(mSettingsFile)); os.print( @@ -720,7 +866,7 @@ public class SettingsStateTest extends AndroidTestCase { int configKey = SettingsState.makeKey(SettingsState.SETTINGS_TYPE_CONFIG, 0); SettingsState settingsState = new SettingsState( - getContext(), mLock, mSettingsFile, configKey, + InstrumentationRegistry.getContext(), mLock, mSettingsFile, configKey, SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper()); Map<String, String> keyValues = diff --git a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java index ea46c0cee6b9..ee81813b4245 100644 --- a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java +++ b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java @@ -300,6 +300,8 @@ public final class RingtonePickerActivity extends AlertActivity implements } }; installTask.execute(data.getData()); + } else if (requestCode == ADD_FILE_REQUEST_CODE && resultCode == RESULT_CANCELED) { + setupAlert(); } } diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index d1a3571a87c1..e63232a87499 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -230,6 +230,7 @@ android_library { extra_check_modules: ["SystemUILintChecker"], warning_checks: ["MissingApacheLicenseDetector"], }, + skip_jarjar_repackage: true, } filegroup { @@ -550,5 +551,6 @@ android_app { required: [ "privapp_whitelist_com.android.systemui", "wmshell.protolog.json.gz", + "wmshell.protolog.pb", ], } diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index a69a2a64dccb..ba7738005de2 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -542,6 +542,23 @@ flag { namespace: "systemui" description: "Binds Keyguard Media Controller Visibility to MediaContainerView" bug: "298213983" +} + +flag { + name: "delayed_wakelock_release_on_background_thread" + namespace: "systemui" + description: "Released delayed wakelocks on background threads to avoid janking screen transitions." + bug: "316128516" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "notify_power_manager_user_activity_background" + namespace: "systemui" + description: "Decide whether to notify the user activity to power manager in the background thread." + bug: "325203885" metadata { purpose: PURPOSE_BUGFIX } diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp index c1125f0b9e92..99b7c36d6fb9 100644 --- a/packages/SystemUI/animation/Android.bp +++ b/packages/SystemUI/animation/Android.bp @@ -45,6 +45,7 @@ android_library { "androidx.core_core-ktx", "androidx.annotation_annotation", "SystemUIShaderLib", + "WindowManager-Shell-shared", "animationlib", ], diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java index a78080fdabf2..e20425d4b98c 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -11,10 +11,10 @@ * 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 + * limitations under the License. */ -package com.android.systemui.shared.system; +package com.android.systemui.animation; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.view.WindowManager.TRANSIT_CLOSE; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationTargetCompat.java index e4d924323bbd..e251af44727e 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationTargetCompat.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.shared.system; +package com.android.systemui.animation; import android.util.ArrayMap; import android.view.RemoteAnimationTarget; diff --git a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt index 62dd4ac8c230..ef15c8461b95 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt @@ -152,7 +152,10 @@ fun PlatformSlider( modifier = Modifier.fillMaxHeight() .weight(1f) - .padding(start = { paddingStart.roundToPx() }), + .padding( + start = { paddingStart.roundToPx() }, + end = { sliderHeight.roundToPx() / 2 }, + ), contentAlignment = Alignment.CenterStart, ) { labelComposable(isDragging) diff --git a/packages/SystemUI/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp index c12084dac9a9..dfb3a55b0966 100644 --- a/packages/SystemUI/compose/features/Android.bp +++ b/packages/SystemUI/compose/features/Android.bp @@ -44,4 +44,5 @@ android_library { ], kotlincflags: ["-Xjvm-default=all"], + skip_jarjar_repackage: true, } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt index be5aa8a4c3b9..7535a51675e3 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt @@ -9,7 +9,7 @@ import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp +import androidx.compose.ui.res.dimensionResource import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.FixedSizeEdgeDetector @@ -29,6 +29,7 @@ import com.android.systemui.communal.shared.model.ObservableCommunalTransitionSt import com.android.systemui.communal.ui.compose.extensions.allowGestures import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel import com.android.systemui.communal.ui.viewmodel.CommunalViewModel +import com.android.systemui.res.R import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.transform @@ -91,7 +92,10 @@ fun CommunalContainer( SceneTransitionLayout( state = sceneTransitionLayoutState, modifier = modifier.fillMaxSize().allowGestures(allowed = touchesAllowed), - swipeSourceDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize), + swipeSourceDetector = + FixedSizeEdgeDetector( + dimensionResource(id = R.dimen.communal_gesture_initiation_width) + ), ) { scene( TransitionSceneKey.Blank, @@ -167,7 +171,3 @@ fun ObservableTransitionState.toModel(): ObservableCommunalTransitionState { ) } } - -object ContainerDimensions { - val EdgeSwipeSize = 40.dp -} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index 622a4f04ee0d..078da1c863ce 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt @@ -17,6 +17,7 @@ package com.android.systemui.communal.ui.compose import android.appwidget.AppWidgetHostView +import android.graphics.drawable.Icon import android.os.Bundle import android.util.SizeF import android.widget.FrameLayout @@ -26,6 +27,7 @@ import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -77,6 +79,8 @@ import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.ColorMatrix import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.LayoutCoordinates @@ -85,8 +89,10 @@ import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.layout.positionInWindow import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId @@ -101,6 +107,8 @@ import androidx.compose.ui.window.Popup import androidx.core.view.setPadding import com.android.compose.modifiers.thenIf import com.android.compose.theme.LocalAndroidColorScheme +import com.android.compose.ui.graphics.painter.rememberDrawablePainter +import com.android.internal.R.dimen.system_app_widget_background_radius import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.ui.compose.Dimensions.CardOutlineWidth @@ -178,7 +186,7 @@ fun CommunalHub( // not display this button. if ( index == null || - communalContent[index].isWidget() || + communalContent[index].isWidgetContent() || communalContent[index] is CommunalContentModel.CtaTileInViewMode ) { isButtonToEditWidgetsShowing = true @@ -274,7 +282,7 @@ private fun BoxScope.CommunalHubLazyGrid( widgetConfigurator: WidgetConfigurator?, ) { var gridModifier = - Modifier.align(Alignment.CenterStart).onGloballyPositioned { setGridCoordinates(it) } + Modifier.align(Alignment.TopStart).onGloballyPositioned { setGridCoordinates(it) } var list = communalContent var dragDropState: GridDragDropState? = null if (viewModel.isEditMode && viewModel is CommunalEditModeViewModel) { @@ -309,8 +317,8 @@ private fun BoxScope.CommunalHubLazyGrid( state = gridState, rows = GridCells.Fixed(CommunalContentSize.FULL.span), contentPadding = contentPadding, - horizontalArrangement = Arrangement.spacedBy(Dimensions.Spacing), - verticalArrangement = Arrangement.spacedBy(Dimensions.Spacing), + horizontalArrangement = Arrangement.spacedBy(32.dp), + verticalArrangement = Arrangement.spacedBy(32.dp), ) { items( count = list.size, @@ -330,7 +338,7 @@ private fun BoxScope.CommunalHubLazyGrid( DraggableItem( dragDropState = dragDropState, selected = selected, - enabled = list[index] is CommunalContentModel.Widget, + enabled = list[index].isWidgetContent(), index = index, ) { isDragging -> CommunalContent( @@ -539,9 +547,11 @@ private fun CommunalContent( widgetConfigurator: WidgetConfigurator? = null, ) { when (model) { - is CommunalContentModel.Widget -> + is CommunalContentModel.WidgetContent.Widget -> WidgetContent(viewModel, model, size, selected, widgetConfigurator, modifier) is CommunalContentModel.WidgetPlaceholder -> HighlightedItem(modifier) + is CommunalContentModel.WidgetContent.DisabledWidget -> + DisabledWidgetPlaceholder(model, modifier) is CommunalContentModel.CtaTileInViewMode -> CtaTileInViewModeContent(viewModel, modifier) is CommunalContentModel.CtaTileInEditMode -> CtaTileInEditModeContent(modifier, onOpenWidgetPicker) @@ -672,7 +682,7 @@ private fun CtaTileInEditModeContent( @Composable private fun WidgetContent( viewModel: BaseCommunalViewModel, - model: CommunalContentModel.Widget, + model: CommunalContentModel.WidgetContent.Widget, size: SizeF, selected: Boolean, widgetConfigurator: WidgetConfigurator?, @@ -681,19 +691,21 @@ private fun WidgetContent( Box( modifier = modifier, ) { - val paddingInPx = with(LocalDensity.current) { CardOutlineWidth.toPx().toInt() } + val paddingInPx = + if (selected) with(LocalDensity.current) { CardOutlineWidth.toPx().toInt() } else 0 AndroidView( modifier = Modifier.fillMaxSize().allowGestures(allowed = !viewModel.isEditMode), factory = { context -> - val view = - model.appWidgetHost - .createViewForCommunal(context, model.appWidgetId, model.providerInfo) - .apply { updateAppWidgetSize(Bundle.EMPTY, listOf(size)) } + model.appWidgetHost + .createViewForCommunal(context, model.appWidgetId, model.providerInfo) + .apply { updateAppWidgetSize(Bundle.EMPTY, listOf(size)) } + }, + update = { view -> // Remove the extra padding applied to AppWidgetHostView to allow widgets to - // occupy the entire box. The added padding is now adjusted to leave only sufficient - // space for displaying the outline around the box when the widget is selected. + // occupy the entire box. The added padding is now adjusted to leave only + // sufficient space for displaying the outline around the box when the widget + // is selected. view.setPadding(paddingInPx) - view }, // For reusing composition in lazy lists. onReset = {}, @@ -716,7 +728,7 @@ private fun WidgetContent( @Composable fun WidgetConfigureButton( visible: Boolean, - model: CommunalContentModel.Widget, + model: CommunalContentModel.WidgetContent.Widget, modifier: Modifier = Modifier, widgetConfigurator: WidgetConfigurator, ) { @@ -751,6 +763,38 @@ fun WidgetConfigureButton( } @Composable +fun DisabledWidgetPlaceholder( + model: CommunalContentModel.WidgetContent.DisabledWidget, + modifier: Modifier = Modifier, +) { + val context = LocalContext.current + val appInfo = model.appInfo + val icon: Icon = + if (appInfo == null || appInfo.icon == 0) { + Icon.createWithResource(context, android.R.drawable.sym_def_app_icon) + } else { + Icon.createWithResource(appInfo.packageName, appInfo.icon) + } + + Column( + modifier = + modifier.background( + MaterialTheme.colorScheme.surfaceVariant, + RoundedCornerShape(dimensionResource(system_app_widget_background_radius)) + ), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Image( + painter = rememberDrawablePainter(icon.loadDrawable(context)), + contentDescription = stringResource(R.string.icon_description_for_disabled_widget), + modifier = Modifier.size(48.dp), + colorFilter = ColorFilter.colorMatrix(Colors.DisabledColorFilter), + ) + } +} + +@Composable private fun SmartspaceContent( model: CommunalContentModel.Smartspace, modifier: Modifier = Modifier, @@ -795,7 +839,7 @@ private fun Umo(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier) @Composable private fun gridContentPadding(isEditMode: Boolean, toolbarSize: IntSize?): PaddingValues { if (!isEditMode || toolbarSize == null) { - return PaddingValues(horizontal = Dimensions.Spacing) + return PaddingValues(start = 48.dp, end = 48.dp, top = Dimensions.GridTopSpacing) } val configuration = LocalConfiguration.current val density = LocalDensity.current @@ -851,19 +895,20 @@ private fun firstIndexAtOffset(gridState: LazyGridState, offset: Offset): Int? = /** Returns the key of item if it's editable at the given index. Only widget is editable. */ private fun keyAtIndexIfEditable(list: List<CommunalContentModel>, index: Int): String? = - if (index in list.indices && list[index].isWidget()) list[index].key else null + if (index in list.indices && list[index].isWidgetContent()) list[index].key else null data class ContentPaddingInPx(val start: Float, val top: Float) { fun toOffset(): Offset = Offset(start, top) } object Dimensions { - val CardWidth = 464.dp - val CardHeightFull = 630.dp - val CardHeightHalf = 307.dp - val CardHeightThird = 199.dp + val CardWidth = 424.dp + val CardHeightFull = 596.dp + val CardHeightHalf = 282.dp + val CardHeightThird = 177.33.dp val CardOutlineWidth = 3.dp - val GridHeight = CardHeightFull + val GridTopSpacing = 72.dp + val GridHeight = CardHeightFull + GridTopSpacing val Spacing = 16.dp // The sizing/padding of the toolbar in glanceable hub edit mode @@ -880,5 +925,30 @@ object Dimensions { val IconSize = 48.dp } +private object Colors { + val DisabledColorFilter by lazy { disabledColorMatrix() } + + /** Returns the disabled image filter. Ported over from [DisableImageView]. */ + private fun disabledColorMatrix(): ColorMatrix { + val brightnessMatrix = ColorMatrix() + val brightnessAmount = 0.5f + val brightnessRgb = (255 * brightnessAmount).toInt().toFloat() + // Brightness: C-new = C-old*(1-amount) + amount + val scale = 1f - brightnessAmount + val mat = brightnessMatrix.values + mat[0] = scale + mat[6] = scale + mat[12] = scale + mat[4] = brightnessRgb + mat[9] = brightnessRgb + mat[14] = brightnessRgb + + return ColorMatrix().apply { + setToSaturation(0F) + timesAssign(brightnessMatrix) + } + } +} + /** The resource id of communal hub accessible from UiAutomator. */ private const val COMMUNAL_HUB_TEST_TAG = "communal_hub" diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt index 9b8c9d0ab616..c5dab3347e5f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/ContentListState.kt @@ -71,8 +71,8 @@ internal constructor( /** Remove widget from the list and the database. */ fun onRemove(indexToRemove: Int) { - if (list[indexToRemove] is CommunalContentModel.Widget) { - val widget = list[indexToRemove] as CommunalContentModel.Widget + if (list[indexToRemove].isWidgetContent()) { + val widget = list[indexToRemove] as CommunalContentModel.WidgetContent list.apply { removeAt(indexToRemove) } onDeleteWidget(widget.appWidgetId) } @@ -100,7 +100,7 @@ internal constructor( val widgetIdToPriorityMap: Map<Int, Int> = list .mapIndexedNotNull { index, item -> - if (item is CommunalContentModel.Widget) { + if (item is CommunalContentModel.WidgetContent) { item.appWidgetId to list.size - index } else { null @@ -115,5 +115,5 @@ internal constructor( } /** Returns true if the item at given index is editable. */ - fun isItemEditable(index: Int) = list[index] is CommunalContentModel.Widget + fun isItemEditable(index: Int) = list[index].isWidgetContent() } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt index be6f022d8d52..31d3fa0be163 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.ui.composable.section import android.content.Context import android.util.DisplayMetrics +import android.view.View import android.view.WindowManager import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -45,6 +46,7 @@ import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R +import com.android.systemui.shade.NotificationPanelView import com.android.systemui.statusbar.VibratorHelper import dagger.Lazy import javax.inject.Inject @@ -63,6 +65,7 @@ constructor( private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>, private val falsingManager: Lazy<FalsingManager>, private val vibratorHelper: Lazy<VibratorHelper>, + private val notificationPanelView: NotificationPanelView, ) { @Composable fun SceneScope.LockIcon(modifier: Modifier = Modifier) { @@ -70,6 +73,10 @@ constructor( return } + notificationPanelView.findViewById<View?>(R.id.lock_icon_view)?.let { + notificationPanelView.removeView(it) + } + val context = LocalContext.current AndroidView( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt index 66cef86fb773..6875bc544a55 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt @@ -40,7 +40,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -51,6 +50,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.res.colorResource import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.TransitionState @@ -62,6 +62,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.qs.footer.ui.compose.FooterActions import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel +import com.android.systemui.res.R import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.ui.composable.ComposableScene import com.android.systemui.scene.ui.composable.asComposeAware @@ -168,7 +169,7 @@ private fun SceneScope.QuickSettingsScene( modifier = Modifier.element(Shade.Elements.BackgroundScrim) .fillMaxSize() - .background(MaterialTheme.colorScheme.scrim) + .background(colorResource(R.color.shade_scrim_background_dark)) ) Column( horizontalAlignment = Alignment.CenterHorizontally, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeAwareExtensions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeAwareExtensions.kt index a7de1eede1f4..0de4650f1248 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeAwareExtensions.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeAwareExtensions.kt @@ -16,9 +16,6 @@ package com.android.systemui.scene.ui.composable -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.ui.unit.Density -import androidx.compose.ui.unit.IntSize import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.Edge as ComposeAwareEdge import com.android.compose.animation.scene.SceneKey as ComposeAwareSceneKey @@ -26,14 +23,12 @@ import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.TransitionKey as ComposeAwareTransitionKey import com.android.compose.animation.scene.UserAction as ComposeAwareUserAction -import com.android.compose.animation.scene.UserActionDistance as ComposeAwareUserActionDistance import com.android.compose.animation.scene.UserActionResult as ComposeAwareUserActionResult import com.android.systemui.scene.shared.model.Direction import com.android.systemui.scene.shared.model.Edge import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.shared.model.TransitionKey import com.android.systemui.scene.shared.model.UserAction -import com.android.systemui.scene.shared.model.UserActionDistance import com.android.systemui.scene.shared.model.UserActionResult // TODO(b/293899074): remove this file once we can use the types from SceneTransitionLayout. @@ -82,22 +77,5 @@ fun UserActionResult.asComposeAware(): ComposeAwareUserActionResult { return ComposeAwareUserActionResult( toScene = composeUnaware.toScene.asComposeAware(), transitionKey = composeUnaware.transitionKey?.asComposeAware(), - distance = composeUnaware.distance?.asComposeAware(), ) } - -fun UserActionDistance.asComposeAware(): ComposeAwareUserActionDistance { - val composeUnware = this - return object : ComposeAwareUserActionDistance { - override fun Density.absoluteDistance( - fromSceneSize: IntSize, - orientation: Orientation, - ): Float { - return composeUnware.absoluteDistance( - fromSceneWidth = fromSceneSize.width, - fromSceneHeight = fromSceneSize.height, - isHorizontal = orientation == Orientation.Horizontal, - ) - } - } -} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt index 2e0ce42ee713..8484b7f5273f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt @@ -26,7 +26,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -37,6 +36,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.Layout import androidx.compose.ui.layout.layout import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.ElementKey @@ -171,7 +171,7 @@ private fun SceneScope.ShadeScene( modifier = modifier .element(Shade.Elements.BackgroundScrim) - .background(MaterialTheme.colorScheme.scrim), + .background(colorResource(R.color.shade_scrim_background_dark)), ) Box { Layout( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponent.kt index d40126198c33..c08eb94f25c0 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponent.kt @@ -19,17 +19,17 @@ package com.android.systemui.volume.panel.component.bottombar.ui import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import com.android.compose.PlatformButton -import com.android.compose.PlatformOutlinedButton import com.android.systemui.res.R import com.android.systemui.volume.panel.component.bottombar.ui.viewmodel.BottomBarViewModel import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope @@ -47,11 +47,11 @@ constructor( @Composable override fun VolumePanelComposeScope.Content(modifier: Modifier) { Row( - modifier = modifier.height(if (isLargeScreen) 54.dp else 48.dp).fillMaxWidth(), + modifier = modifier.heightIn(min = if (isLargeScreen) 54.dp else 48.dp).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { - PlatformOutlinedButton( + OutlinedButton( onClick = viewModel::onSettingsClicked, colors = ButtonDefaults.outlinedButtonColors( @@ -60,8 +60,8 @@ constructor( ) { Text(text = stringResource(R.string.volume_panel_dialog_settings_button)) } - PlatformButton(onClick = viewModel::onDoneClicked) { - Text(text = stringResource(R.string.inline_done_button)) + Button(onClick = viewModel::onDoneClicked) { + Text(stringResource(R.string.inline_done_button)) } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt index d49fed5d6e10..b3fcc305e6b5 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt @@ -27,6 +27,7 @@ import androidx.compose.animation.scaleOut import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically import androidx.compose.animation.togetherWith +import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -46,7 +47,6 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.android.compose.animation.Expandable import com.android.systemui.common.ui.compose.Icon @@ -78,8 +78,8 @@ constructor( color = MaterialTheme.colorScheme.surface, shape = RoundedCornerShape(28.dp), onClick = { viewModel.onBarClick(it) }, - ) { - Row { + ) { _ -> + Row(verticalAlignment = Alignment.CenterVertically) { connectedDeviceViewModel?.let { ConnectedDeviceText(it) } deviceIconViewModel?.let { ConnectedDeviceIcon(it) } @@ -90,26 +90,23 @@ constructor( @Composable private fun RowScope.ConnectedDeviceText(connectedDeviceViewModel: ConnectedDeviceViewModel) { Column( - modifier = - Modifier.weight(1f) - .padding(start = 24.dp, top = 20.dp, bottom = 20.dp) - .fillMaxHeight(), + modifier = Modifier.weight(1f).padding(start = 24.dp), verticalArrangement = Arrangement.spacedBy(4.dp), ) { Text( - connectedDeviceViewModel.label.toString(), + modifier = Modifier.basicMarquee(), + text = connectedDeviceViewModel.label.toString(), style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 1, - overflow = TextOverflow.Ellipsis, ) connectedDeviceViewModel.deviceName?.let { Text( - it.toString(), + modifier = Modifier.basicMarquee(), + text = it.toString(), style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurface, maxLines = 1, - overflow = TextOverflow.Ellipsis, ) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt index a197a4b0fd55..4d810dfce89d 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt @@ -66,7 +66,7 @@ fun ColumnVolumeSliders( modifier: Modifier = Modifier, ) { require(viewModels.isNotEmpty()) - var isExpanded: Boolean by remember { mutableStateOf(false) } + var isExpanded: Boolean by remember(isExpandable) { mutableStateOf(!isExpandable) } val transition = updateTransition(isExpanded, label = "CollapsableSliders") Column(modifier = modifier) { Row( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt index 5925b1482e77..18a62dca3769 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt @@ -20,6 +20,7 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.animateContentSize import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically +import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.layout.Column import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -41,7 +42,7 @@ fun VolumeSlider( modifier: Modifier = Modifier, sliderColors: PlatformSliderColors, ) { - var value by remember { mutableFloatStateOf(state.value) } + var value by remember(state.value) { mutableFloatStateOf(state.value) } PlatformSlider( modifier = modifier, value = value, @@ -59,7 +60,12 @@ fun VolumeSlider( colors = sliderColors, label = { Column(modifier = Modifier.animateContentSize()) { - Text(state.label, style = MaterialTheme.typography.titleMedium) + Text( + modifier = Modifier.basicMarquee(), + text = state.label, + style = MaterialTheme.typography.titleMedium, + maxLines = 1, + ) state.disabledMessage?.let { message -> AnimatedVisibility( @@ -67,7 +73,12 @@ fun VolumeSlider( enter = expandVertically { it }, exit = shrinkVertically { it }, ) { - Text(text = message, style = MaterialTheme.typography.bodySmall) + Text( + modifier = Modifier.basicMarquee(), + text = message, + style = MaterialTheme.typography.bodySmall, + maxLines = 1, + ) } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt index 6213dc5f63c9..1ca18deeaac2 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt @@ -26,6 +26,7 @@ import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.Sl import com.android.systemui.volume.panel.component.volume.ui.viewmodel.AudioVolumeComponentViewModel import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope +import com.android.systemui.volume.panel.ui.composable.isPortrait import javax.inject.Inject class VolumeSlidersComponent @@ -50,7 +51,7 @@ constructor( ColumnVolumeSliders( viewModels = sliderViewModels, sliderColors = PlatformSliderDefaults.defaultPlatformSliderColors(), - isExpandable = true, + isExpandable = isPortrait, modifier = modifier.fillMaxWidth(), ) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/HorizontalVolumePanelContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/HorizontalVolumePanelContent.kt index 0a651c898aba..ac5004e16a3b 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/HorizontalVolumePanelContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/HorizontalVolumePanelContent.kt @@ -21,7 +21,8 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -36,7 +37,7 @@ fun VolumePanelComposeScope.HorizontalVolumePanelContent( val spacing = 20.dp Row(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(space = spacing)) { Column( - modifier = Modifier.weight(1f), + modifier = Modifier.weight(1f).verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(spacing) ) { for (component in layout.contentComponents) { @@ -47,7 +48,7 @@ fun VolumePanelComposeScope.HorizontalVolumePanelContent( } Column( - modifier = Modifier.weight(1f), + modifier = Modifier.weight(1f).verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(space = spacing, alignment = Alignment.Top) ) { for (component in layout.headerComponents) { @@ -56,7 +57,7 @@ fun VolumePanelComposeScope.HorizontalVolumePanelContent( } } Row( - modifier = Modifier.fillMaxWidth().wrapContentHeight(), + modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(spacing), ) { for (component in layout.footerComponents) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt index 4d073798c70c..dd767817a5ae 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt @@ -22,6 +22,8 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @@ -33,7 +35,7 @@ fun VolumePanelComposeScope.VerticalVolumePanelContent( modifier: Modifier = Modifier, ) { Column( - modifier = modifier, + modifier = modifier.verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(20.dp), ) { for (component in layout.headerComponents) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt index 8a1e6a8b74f4..910cd5ec107b 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt @@ -16,12 +16,13 @@ package com.android.systemui.volume.panel.ui.composable -import android.content.res.Configuration import androidx.compose.foundation.clickable import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.heightIn @@ -37,13 +38,17 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.max import com.android.compose.theme.PlatformTheme import com.android.systemui.res.R import com.android.systemui.volume.panel.ui.layout.ComponentsLayout import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelState import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel +import kotlin.math.max private val padding = 24.dp @@ -66,12 +71,12 @@ fun VolumePanelRoot( val components by viewModel.componentsLayout.collectAsState(null) with(VolumePanelComposeScope(state)) { - var boxModifier = modifier.fillMaxSize().clickable(onClick = onDismiss) - if (!isPortrait) { - boxModifier = boxModifier.padding(horizontal = 48.dp) - } Box( - modifier = boxModifier, + modifier = + modifier + .fillMaxSize() + .clickable(onClick = onDismiss) + .volumePanelPaddings(isPortrait = isPortrait), contentAlignment = Alignment.BottomCenter, ) { val radius = dimensionResource(R.dimen.volume_panel_corner_radius) @@ -81,8 +86,8 @@ fun VolumePanelRoot( interactionSource = null, indication = null, onClick = { - // prevent windowCloseOnTouchOutside from dismissing when tapped on - // the panel itself. + // prevent windowCloseOnTouchOutside from dismissing when tapped + // on the panel itself. }, ), shape = RoundedCornerShape(topStart = radius, topEnd = radius), @@ -111,17 +116,31 @@ private fun VolumePanelComposeScope.Components( layout: ComponentsLayout, modifier: Modifier = Modifier ) { - var columnModifier = modifier.widthIn(max = 800.dp) - if (!isLargeScreen && orientation != Configuration.ORIENTATION_PORTRAIT) { - columnModifier = columnModifier.heightIn(max = 332.dp) - } - Column(modifier = columnModifier, verticalArrangement = Arrangement.spacedBy(padding)) { - if (orientation == Configuration.ORIENTATION_PORTRAIT || isLargeScreen) { - VerticalVolumePanelContent(layout) + val arrangement: Arrangement.Vertical = + if (isLargeScreen) { + Arrangement.spacedBy(20.dp) } else { - HorizontalVolumePanelContent(layout) + if (isPortrait) Arrangement.spacedBy(padding) else Arrangement.spacedBy(4.dp) } - BottomBar(layout = layout, modifier = Modifier) + Column( + modifier = modifier.widthIn(max = 800.dp), + verticalArrangement = arrangement, + ) { + if (isPortrait || isLargeScreen) { + VerticalVolumePanelContent( + modifier = Modifier.weight(weight = 1f, fill = false), + layout = layout + ) + } else { + HorizontalVolumePanelContent( + modifier = Modifier.weight(weight = 1f, fill = false).heightIn(max = 212.dp), + layout = layout, + ) + } + BottomBar( + modifier = Modifier, + layout = layout, + ) } } @@ -141,3 +160,28 @@ private fun VolumePanelComposeScope.BottomBar( } } } + +/** + * Makes sure volume panel stays symmetrically in the middle of the screen while still avoiding + * being under the cutouts. + */ +@Composable +private fun Modifier.volumePanelPaddings(isPortrait: Boolean): Modifier { + val cutout = WindowInsets.displayCutout + return with(LocalDensity.current) { + val horizontalCutout = + max( + cutout.getLeft(density = this, layoutDirection = LocalLayoutDirection.current), + cutout.getRight(density = this, layoutDirection = LocalLayoutDirection.current) + ) + val minHorizontalPadding = if (isPortrait) 0.dp else 48.dp + val horizontalPadding = max(horizontalCutout.toDp(), minHorizontalPadding) + + padding( + start = horizontalPadding, + top = cutout.getTop(this).toDp(), + end = horizontalPadding, + bottom = cutout.getBottom(this).toDp(), + ) + } +} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt index 76e7c95f274a..b94e49bb0edc 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/DraggableHandler.kt @@ -27,7 +27,6 @@ import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.round @@ -37,41 +36,38 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.launch -internal class SceneGestureHandler( - internal val layoutImpl: SceneTransitionLayoutImpl, - internal val orientation: Orientation, - private val coroutineScope: CoroutineScope, -) { - private val layoutState = layoutImpl.state - val draggable: DraggableHandler = SceneDraggableHandler(this) - - private var _swipeTransition: SwipeTransition? = null - private var swipeTransition: SwipeTransition - get() = _swipeTransition ?: error("SwipeTransition needs to be initialized") - set(value) { - _swipeTransition = value - } +interface DraggableHandler { + /** + * Start a drag in the given [startedPosition], with the given [overSlop] and number of + * [pointersDown]. + * + * The returned [DragController] should be used to continue or stop the drag. + */ + fun onDragStarted(startedPosition: Offset?, overSlop: Float, pointersDown: Int): DragController +} - private fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) { - if (isDrivingTransition || force) { - layoutState.startTransition(newTransition, newTransition.key) +/** + * The [DragController] provides control over the transition between two scenes through the [onDrag] + * and [onStop] methods. + */ +interface DragController { + /** Drag the current scene by [delta] pixels. */ + fun onDrag(delta: Float) - // Initialize SwipeTransition.swipeSpec. Note that this must be called right after - // layoutState.startTransition() is called, because it computes the - // layoutState.transformationSpec(). - newTransition.swipeSpec = - layoutState.transformationSpec.swipeSpec ?: layoutState.transitions.defaultSwipeSpec - } else { - // We were not driving the transition and we don't force the update, so the spec won't - // be used and it doesn't matter which one we set here. - newTransition.swipeSpec = SceneTransitions.DefaultSwipeSpec - } + /** Starts a transition to a target scene. */ + fun onStop(velocity: Float, canChangeScene: Boolean) +} - swipeTransition = newTransition - } +internal class DraggableHandlerImpl( + internal val layoutImpl: SceneTransitionLayoutImpl, + internal val orientation: Orientation, + internal val coroutineScope: CoroutineScope, +) : DraggableHandler { + /** The [DraggableHandler] can only have one active [DragController] at a time. */ + private var dragController: DragControllerImpl? = null - internal val isDrivingTransition - get() = layoutState.transitionState == _swipeTransition + internal val isDrivingTransition: Boolean + get() = dragController?.isDrivingTransition == true /** * The velocity threshold at which the intent of the user is to swipe up or down. It is the same @@ -84,14 +80,9 @@ internal class SceneGestureHandler( * The positional threshold at which the intent of the user is to swipe to the next scene. It is * the same as SwipeableV2Defaults.PositionalThreshold. */ - private val positionalThreshold + internal val positionalThreshold get() = with(layoutImpl.density) { 56.dp.toPx() } - internal var currentSource: Any? = null - - /** The [Swipes] associated to the current gesture. */ - private var swipes: Swipes? = null - /** * Whether we should immediately intercept a gesture. * @@ -100,35 +91,52 @@ internal class SceneGestureHandler( */ internal fun shouldImmediatelyIntercept(startedPosition: Offset?): Boolean { // We don't intercept the touch if we are not currently driving the transition. - if (!isDrivingTransition) { + val dragController = dragController + if (dragController?.isDrivingTransition != true) { return false } // Only intercept the current transition if one of the 2 swipes results is also a transition // between the same pair of scenes. + val swipeTransition = dragController.swipeTransition val fromScene = swipeTransition._currentScene val swipes = computeSwipes(fromScene, startedPosition, pointersDown = 1) - val (upOrLeft, downOrRight) = computeSwipesResults(fromScene, swipes) + val (upOrLeft, downOrRight) = swipes.computeSwipesResults(fromScene) return (upOrLeft != null && swipeTransition.isTransitioningBetween(fromScene.key, upOrLeft.toScene)) || (downOrRight != null && swipeTransition.isTransitioningBetween(fromScene.key, downOrRight.toScene)) } - internal fun onDragStarted(pointersDown: Int, startedPosition: Offset?, overSlop: Float) { + override fun onDragStarted( + startedPosition: Offset?, + overSlop: Float, + pointersDown: Int, + ): DragController { if (overSlop == 0f) { - check(isDrivingTransition) { - "onDragStarted() called while isDrivingTransition=false overSlop=0f" + val oldDragController = dragController + check(oldDragController != null && oldDragController.isDrivingTransition) { + val isActive = oldDragController?.isDrivingTransition + "onDragStarted(overSlop=0f) requires an active dragController, but was $isActive" } // This [transition] was already driving the animation: simply take over it. // Stop animating and start from where the current offset. - swipeTransition.cancelOffsetAnimation() - swipes!!.updateSwipesResults(swipeTransition._fromScene) - return + oldDragController.swipeTransition.cancelOffsetAnimation() + + // We need to recompute the swipe results since this is a new gesture, and the + // fromScene.userActions may have changed. + val swipes = oldDragController.swipes + swipes.updateSwipesResults(oldDragController.swipeTransition._fromScene) + + // A new gesture should always create a new SwipeTransition. This way there cannot be + // different gestures controlling the same transition. + val swipeTransition = SwipeTransition(oldDragController.swipeTransition) + swipes.updateSwipesResults(fromScene = swipeTransition._fromScene) + return updateDragController(swipes, swipeTransition) } - val transitionState = layoutState.transitionState + val transitionState = layoutImpl.state.transitionState if (transitionState is TransitionState.Transition) { // TODO(b/290184746): Better handle interruptions here if state != idle. Log.w( @@ -140,24 +148,27 @@ internal class SceneGestureHandler( } val fromScene = layoutImpl.scene(transitionState.currentScene) - val newSwipes = computeSwipes(fromScene, startedPosition, pointersDown) - swipes = newSwipes - val result = newSwipes.findUserActionResult(fromScene, overSlop, true) + val swipes = computeSwipes(fromScene, startedPosition, pointersDown) + val result = swipes.findUserActionResult(fromScene, overSlop, true) // As we were unable to locate a valid target scene, the initial SwipeTransition cannot be - // defined. - if (result == null) return + // defined. Consequently, a simple NoOp Controller will be returned. + if (result == null) return NoOpDragController - val newSwipeTransition = - SwipeTransition( - fromScene = fromScene, - result = result, - swipes = newSwipes, - layoutImpl = layoutImpl, - orientation = orientation - ) + return updateDragController( + swipes = swipes, + swipeTransition = SwipeTransition(fromScene, result, swipes, layoutImpl, orientation) + ) + } - updateTransition(newSwipeTransition, force = true) + private fun updateDragController( + swipes: Swipes, + swipeTransition: SwipeTransition + ): DragController { + val newDragController = DragControllerImpl(this, swipes, swipeTransition) + newDragController.updateTransition(swipeTransition, force = true) + dragController = newDragController + return newDragController } private fun computeSwipes( @@ -214,7 +225,58 @@ internal class SceneGestureHandler( } } - internal fun onDrag(delta: Float) { + companion object { + private const val TAG = "DraggableHandlerImpl" + } +} + +/** @param swipes The [Swipes] associated to the current gesture. */ +private class DragControllerImpl( + private val draggableHandler: DraggableHandlerImpl, + val swipes: Swipes, + var swipeTransition: SwipeTransition, +) : DragController { + val layoutState = draggableHandler.layoutImpl.state + + /** + * Whether this handle is active. If this returns false, calling [onDrag] and [onStop] will do + * nothing. We should have only one active controller at a time + */ + val isDrivingTransition: Boolean + get() = layoutState.transitionState == swipeTransition + + init { + check(!isDrivingTransition) { "Multiple controllers with the same SwipeTransition" } + } + + fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) { + if (isDrivingTransition || force) { + layoutState.startTransition(newTransition, newTransition.key) + + // Initialize SwipeTransition.transformationSpec and .swipeSpec. Note that this must be + // called right after layoutState.startTransition() is called, because it computes the + // current layoutState.transformationSpec(). + val transformationSpec = layoutState.transformationSpec + newTransition.transformationSpec = transformationSpec + newTransition.swipeSpec = + transformationSpec.swipeSpec ?: layoutState.transitions.defaultSwipeSpec + } else { + // We were not driving the transition and we don't force the update, so the specs won't + // be used and it doesn't matter which ones we set here. + newTransition.transformationSpec = TransformationSpec.Empty + newTransition.swipeSpec = SceneTransitions.DefaultSwipeSpec + } + + swipeTransition = newTransition + } + + /** + * We receive a [delta] that can be consumed to change the offset of the current + * [SwipeTransition]. + * + * @return the consumed delta + */ + override fun onDrag(delta: Float) { if (delta == 0f || !isDrivingTransition) return swipeTransition.dragOffset += delta @@ -223,14 +285,14 @@ internal class SceneGestureHandler( val isNewFromScene = fromScene.key != swipeTransition.fromScene val result = - swipes!!.findUserActionResult( + swipes.findUserActionResult( fromScene = fromScene, directionOffset = swipeTransition.dragOffset, updateSwipesResults = isNewFromScene ) if (result == null) { - onDragStopped(velocity = delta, canChangeScene = true) + onStop(velocity = delta, canChangeScene = true) return } @@ -241,36 +303,20 @@ internal class SceneGestureHandler( result.toScene != swipeTransition.toScene || result.transitionKey != swipeTransition.key ) { - val newSwipeTransition = + val swipeTransition = SwipeTransition( fromScene = fromScene, result = result, - swipes = swipes!!, - layoutImpl = layoutImpl, - orientation = orientation + swipes = swipes, + layoutImpl = draggableHandler.layoutImpl, + orientation = draggableHandler.orientation, ) .apply { dragOffset = swipeTransition.dragOffset } - updateTransition(newSwipeTransition) + updateTransition(swipeTransition) } } - private fun computeSwipesResults( - fromScene: Scene, - swipes: Swipes - ): Pair<UserActionResult?, UserActionResult?> { - val userActions = fromScene.userActions - fun sceneToSwipePair(swipe: Swipe?): UserActionResult? { - return userActions[swipe ?: return null] - } - - val upOrLeftResult = - sceneToSwipePair(swipes.upOrLeft) ?: sceneToSwipePair(swipes.upOrLeftNoSource) - val downOrRightResult = - sceneToSwipePair(swipes.downOrRight) ?: sceneToSwipePair(swipes.downOrRightNoSource) - return Pair(upOrLeftResult, downOrRightResult) - } - /** * Change fromScene in the case where the user quickly swiped multiple times in the same * direction to accelerate the transition from A => B then B => C. @@ -285,28 +331,37 @@ internal class SceneGestureHandler( ): Pair<Scene, Float> { val toScene = swipeTransition._toScene val fromScene = swipeTransition._fromScene - val absoluteDistance = swipeTransition.distance.absoluteValue + val distance = swipeTransition.distance() - // If the swipe was not committed, don't do anything. - if (swipeTransition._currentScene != toScene) { + // If the swipe was not committed or if the swipe distance is not computed yet, don't do + // anything. + if ( + swipeTransition._currentScene != toScene || + distance == SwipeTransition.DistanceUnspecified + ) { return fromScene to 0f } // If the offset is past the distance then let's change fromScene so that the user can swipe // to the next screen or go back to the previous one. val offset = swipeTransition.dragOffset - return if (offset <= -absoluteDistance && swipes!!.upOrLeftResult?.toScene == toScene.key) { + val absoluteDistance = distance.absoluteValue + return if (offset <= -absoluteDistance && swipes.upOrLeftResult?.toScene == toScene.key) { toScene to absoluteDistance - } else if ( - offset >= absoluteDistance && swipes!!.downOrRightResult?.toScene == toScene.key - ) { + } else if (offset >= absoluteDistance && swipes.downOrRightResult?.toScene == toScene.key) { toScene to -absoluteDistance } else { fromScene to 0f } } - internal fun onDragStopped(velocity: Float, canChangeScene: Boolean) { + private fun snapToScene(scene: SceneKey) { + if (!isDrivingTransition) return + swipeTransition.cancelOffsetAnimation() + layoutState.finishTransition(swipeTransition, idleScene = scene) + } + + override fun onStop(velocity: Float, canChangeScene: Boolean) { // The state was changed since the drag started; don't do anything. if (!isDrivingTransition) { return @@ -325,16 +380,16 @@ internal class SceneGestureHandler( // immediately go back B => A. if (targetScene != swipeTransition._currentScene) { swipeTransition._currentScene = targetScene - with(layoutImpl.state) { coroutineScope.onChangeScene(targetScene.key) } + with(draggableHandler.layoutImpl.state) { + draggableHandler.coroutineScope.onChangeScene(targetScene.key) + } } swipeTransition.animateOffset( - coroutineScope = coroutineScope, + coroutineScope = draggableHandler.coroutineScope, initialVelocity = velocity, targetOffset = targetOffset, - onAnimationCompleted = { - layoutState.finishTransition(swipeTransition, idleScene = targetScene.key) - } + onAnimationCompleted = { snapToScene(targetScene.key) } ) } @@ -347,16 +402,17 @@ internal class SceneGestureHandler( // Compute the destination scene (and therefore offset) to settle in. val offset = swipeTransition.dragOffset - val distance = swipeTransition.distance + val distance = swipeTransition.distance() var targetScene: Scene var targetOffset: Float if ( - shouldCommitSwipe( - offset, - distance, - velocity, - wasCommitted = swipeTransition._currentScene == toScene, - ) + distance != SwipeTransition.DistanceUnspecified && + shouldCommitSwipe( + offset, + distance, + velocity, + wasCommitted = swipeTransition._currentScene == toScene, + ) ) { targetScene = toScene targetOffset = distance @@ -372,7 +428,15 @@ internal class SceneGestureHandler( // We wanted to change to a new scene but we are not allowed to, so we animate back // to the current scene. targetScene = swipeTransition._currentScene - targetOffset = if (targetScene == fromScene) 0f else distance + targetOffset = + if (targetScene == fromScene) { + 0f + } else { + check(distance != SwipeTransition.DistanceUnspecified) { + "distance is equal to ${SwipeTransition.DistanceUnspecified}" + } + distance + } } animateTo(targetScene = targetScene, targetOffset = targetOffset) @@ -384,10 +448,10 @@ internal class SceneGestureHandler( if (startFromIdlePosition) { // If there is a target scene, we start the overscroll animation. - val result = swipes!!.findUserActionResultStrict(velocity) + val result = swipes.findUserActionResultStrict(velocity) if (result == null) { // We will not animate - layoutState.finishTransition(swipeTransition, idleScene = fromScene.key) + snapToScene(fromScene.key) return } @@ -395,9 +459,9 @@ internal class SceneGestureHandler( SwipeTransition( fromScene = fromScene, result = result, - swipes = swipes!!, - layoutImpl = layoutImpl, - orientation = orientation + swipes = swipes, + layoutImpl = draggableHandler.layoutImpl, + orientation = draggableHandler.orientation, ) .apply { _currentScene = swipeTransition._currentScene } @@ -424,6 +488,9 @@ internal class SceneGestureHandler( return (offset - distance).absoluteValue < offset.absoluteValue } + val velocityThreshold = draggableHandler.velocityThreshold + val positionalThreshold = draggableHandler.positionalThreshold + // Swiping up or left. if (distance < 0f) { return if (offset > 0f || velocity >= velocityThreshold) { @@ -444,10 +511,6 @@ internal class SceneGestureHandler( isCloserToTarget() } } - - companion object { - private const val TAG = "SceneGestureHandler" - } } private fun SwipeTransition( @@ -459,42 +522,64 @@ private fun SwipeTransition( ): SwipeTransition { val upOrLeftResult = swipes.upOrLeftResult val downOrRightResult = swipes.downOrRightResult - val userActionDistance = result.distance ?: DefaultSwipeDistance - val absoluteDistance = - with(userActionDistance) { - layoutImpl.density.absoluteDistance(fromScene.targetSize, orientation) + val isUpOrLeft = + when (result) { + upOrLeftResult -> true + downOrRightResult -> false + else -> error("Unknown result $result ($upOrLeftResult $downOrRightResult)") } return SwipeTransition( key = result.transitionKey, _fromScene = fromScene, _toScene = layoutImpl.scene(result.toScene), - distance = - when (result) { - upOrLeftResult -> -absoluteDistance - downOrRightResult -> absoluteDistance - else -> error("Unknown result $result ($upOrLeftResult $downOrRightResult)") - }, + userActionDistanceScope = layoutImpl.userActionDistanceScope, + orientation = orientation, + isUpOrLeft = isUpOrLeft, ) } +private fun SwipeTransition(old: SwipeTransition): SwipeTransition { + return SwipeTransition( + key = old.key, + _fromScene = old._fromScene, + _toScene = old._toScene, + userActionDistanceScope = old.userActionDistanceScope, + orientation = old.orientation, + isUpOrLeft = old.isUpOrLeft + ) + .apply { + _currentScene = old._currentScene + dragOffset = old.dragOffset + } +} + private class SwipeTransition( val key: TransitionKey?, val _fromScene: Scene, val _toScene: Scene, - /** - * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is above - * or to the left of [toScene] - */ - val distance: Float, -) : TransitionState.Transition(_fromScene.key, _toScene.key) { + val userActionDistanceScope: UserActionDistanceScope, + override val orientation: Orientation, + override val isUpOrLeft: Boolean, +) : + TransitionState.Transition(_fromScene.key, _toScene.key), + TransitionState.HasOverscrollProperties { var _currentScene by mutableStateOf(_fromScene) override val currentScene: SceneKey get() = _currentScene.key override val progress: Float get() { + // Important: If we are going to return early because distance is equal to 0, we should + // still make sure we read the offset before returning so that the calling code still + // subscribes to the offset value. val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset + + val distance = distance() + if (distance == DistanceUnspecified) { + return 0f + } + return offset / distance } @@ -518,9 +603,50 @@ private class SwipeTransition( /** Job to check that there is at most one offset animation in progress. */ private var offsetAnimationJob: Job? = null + /** + * The [TransformationSpecImpl] associated to this transition. + * + * Note: This is lateinit because this [SwipeTransition] is needed by + * [BaseSceneTransitionLayoutState] to compute the [TransitionSpec], and it will be set right + * after [BaseSceneTransitionLayoutState.startTransition] is called with this transition. + */ + lateinit var transformationSpec: TransformationSpecImpl + /** The spec to use when animating this transition to either [fromScene] or [toScene]. */ lateinit var swipeSpec: SpringSpec<Float> + private var lastDistance = DistanceUnspecified + + /** + * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is above + * or to the left of [toScene]. + * + * Note that this distance can be equal to [DistanceUnspecified] during the first frame of a + * transition when the distance depends on the size or position of an element that is composed + * in the scene we are going to. + */ + fun distance(): Float { + if (lastDistance != DistanceUnspecified) { + return lastDistance + } + + val absoluteDistance = + with(transformationSpec.distance ?: DefaultSwipeDistance) { + userActionDistanceScope.absoluteDistance( + _fromScene.targetSize, + orientation, + ) + } + + if (absoluteDistance <= 0f) { + return DistanceUnspecified + } + + val distance = if (isUpOrLeft) -absoluteDistance else absoluteDistance + lastDistance = distance + return distance + } + /** Ends any previous [offsetAnimationJob] and runs the new [job]. */ private fun startOffsetAnimation(job: () -> Job) { cancelOffsetAnimation() @@ -563,6 +689,7 @@ private class SwipeTransition( } isAnimatingOffset = true + val animationSpec = transformationSpec offsetAnimatable.animateTo( targetValue = targetOffset, animationSpec = swipeSpec, @@ -571,10 +698,14 @@ private class SwipeTransition( finishOffsetAnimation() } + + companion object { + const val DistanceUnspecified = 0f + } } private object DefaultSwipeDistance : UserActionDistance { - override fun Density.absoluteDistance( + override fun UserActionDistanceScope.absoluteDistance( fromSceneSize: IntSize, orientation: Orientation, ): Float { @@ -661,40 +792,16 @@ private class Swipes( } } -private class SceneDraggableHandler( - private val gestureHandler: SceneGestureHandler, -) : DraggableHandler { - private val source = this - - override fun onDragStarted(startedPosition: Offset, overSlop: Float, pointersDown: Int) { - gestureHandler.currentSource = source - gestureHandler.onDragStarted(pointersDown, startedPosition, overSlop) - } - - override fun onDelta(pixels: Float) { - if (gestureHandler.currentSource == source) { - gestureHandler.onDrag(delta = pixels) - } - } - - override fun onDragStopped(velocity: Float) { - if (gestureHandler.currentSource == source) { - gestureHandler.currentSource = null - gestureHandler.onDragStopped(velocity = velocity, canChangeScene = true) - } - } -} - -internal class SceneNestedScrollHandler( +internal class NestedScrollHandlerImpl( private val layoutImpl: SceneTransitionLayoutImpl, private val orientation: Orientation, private val topOrLeftBehavior: NestedScrollBehavior, private val bottomOrRightBehavior: NestedScrollBehavior, -) : NestedScrollHandler { +) { private val layoutState = layoutImpl.state - private val gestureHandler = layoutImpl.gestureHandler(orientation) + private val draggableHandler = layoutImpl.draggableHandler(orientation) - override val connection: PriorityNestedScrollConnection = nestedScrollConnection() + val connection: PriorityNestedScrollConnection = nestedScrollConnection() private fun nestedScrollConnection(): PriorityNestedScrollConnection { // If we performed a long gesture before entering priority mode, we would have to avoid @@ -722,17 +829,24 @@ internal class SceneNestedScrollHandler( ) fun hasNextScene(amount: Float): Boolean { - val fromScene = layoutImpl.scene(layoutState.transitionState.currentScene) + val transitionState = layoutState.transitionState + val scene = transitionState.currentScene + val fromScene = layoutImpl.scene(scene) val nextScene = when { amount < 0f -> fromScene.userActions[actionUpOrLeft] amount > 0f -> fromScene.userActions[actionDownOrRight] else -> null } - return nextScene != null + if (nextScene != null) return true + + if (transitionState !is TransitionState.Idle) return false + + val overscrollSpec = layoutImpl.state.transitions.overscrollSpec(scene, orientation) + return overscrollSpec != null } - val source = this + var dragController: DragController? = null var isIntercepting = false return PriorityNestedScrollConnection( @@ -743,7 +857,7 @@ internal class SceneNestedScrollHandler( val canInterceptSwipeTransition = canChangeScene && offsetAvailable != 0f && - gestureHandler.shouldImmediatelyIntercept(startedPosition = null) + draggableHandler.shouldImmediatelyIntercept(startedPosition = null) if (!canInterceptSwipeTransition) return@PriorityNestedScrollConnection false val threshold = layoutImpl.transitionInterceptionThreshold @@ -817,34 +931,28 @@ internal class SceneNestedScrollHandler( canContinueScroll = { true }, canScrollOnFling = false, onStart = { offsetAvailable -> - gestureHandler.currentSource = source - gestureHandler.onDragStarted( - pointersDown = 1, - startedPosition = null, - overSlop = if (isIntercepting) 0f else offsetAvailable, - ) + dragController = + draggableHandler.onDragStarted( + pointersDown = 1, + startedPosition = null, + overSlop = if (isIntercepting) 0f else offsetAvailable, + ) }, onScroll = { offsetAvailable -> - if (gestureHandler.currentSource != source) { - return@PriorityNestedScrollConnection 0f - } + val controller = dragController ?: error("Should be called after onStart") // TODO(b/297842071) We should handle the overscroll or slow drag if the gesture is // initiated in a nested child. - gestureHandler.onDrag(offsetAvailable) + controller.onDrag(delta = offsetAvailable) offsetAvailable }, onStop = { velocityAvailable -> - if (gestureHandler.currentSource != source) { - return@PriorityNestedScrollConnection 0f - } + val controller = dragController ?: error("Should be called after onStart") - gestureHandler.onDragStopped( - velocity = velocityAvailable, - canChangeScene = canChangeScene - ) + controller.onStop(velocity = velocityAvailable, canChangeScene = canChangeScene) + dragController = null // The onDragStopped animation consumes any remaining velocity. velocityAvailable }, @@ -859,3 +967,9 @@ internal class SceneNestedScrollHandler( // TODO(b/290184746): Have a better default visibility threshold which takes the swipe distance into // account instead. internal const val OffsetVisibilityThreshold = 0.5f + +private object NoOpDragController : DragController { + override fun onDrag(delta: Float) {} + + override fun onStop(velocity: Float, canChangeScene: Boolean) {} +} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt index 2e781e69bb4a..c7186da6b961 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt @@ -39,7 +39,6 @@ import androidx.compose.ui.layout.Placeable import androidx.compose.ui.node.DrawModifierNode import androidx.compose.ui.node.ModifierNodeElement import androidx.compose.ui.platform.testTag -import androidx.compose.ui.semantics.testTag import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.round @@ -204,6 +203,17 @@ internal class ElementNode( measurable: Measurable, constraints: Constraints, ): MeasureResult { + val overscrollScene = layoutImpl.state.currentOverscrollSpec?.scene + if (overscrollScene != null && overscrollScene != scene.key) { + // There is an overscroll in progress on another scene + // By measuring composable elements, Compose can cache relevant information. + // This reduces the need for re-measure when users return from an overscroll animation. + val placeable = measurable.measure(constraints) + return layout(placeable.width, placeable.height) { + // We don't want to draw it, no need to place the element. + } + } + val placeable = measure(layoutImpl, scene, element, sceneState, measurable, constraints) return layout(placeable.width, placeable.height) { place(layoutImpl, scene, element, sceneState, placeable, placementScope = this) @@ -253,11 +263,13 @@ private fun shouldDrawElement( ): Boolean { val transition = layoutImpl.state.currentTransition - // Always draw the element if there is no ongoing transition or if the element is not shared. + // Always draw the element if there is no ongoing transition or if the element is not shared or + // if the current scene is the one that is currently over scrolling with [OverscrollSpec]. if ( transition == null || transition.fromScene !in element.sceneStates || - transition.toScene !in element.sceneStates + transition.toScene !in element.sceneStates || + layoutImpl.state.currentOverscrollSpec?.scene == scene.key ) { return true } @@ -286,12 +298,14 @@ internal fun shouldDrawOrComposeSharedElement( val fromScene = transition.fromScene val toScene = transition.toScene - return scenePicker.sceneDuringTransition( - element = element, - transition = transition, - fromSceneZIndex = layoutImpl.scenes.getValue(fromScene).zIndex, - toSceneZIndex = layoutImpl.scenes.getValue(toScene).zIndex, - ) == scene + val chosenByPicker = + scenePicker.sceneDuringTransition( + element = element, + transition = transition, + fromSceneZIndex = layoutImpl.scenes.getValue(fromScene).zIndex, + toSceneZIndex = layoutImpl.scenes.getValue(toScene).zIndex, + ) == scene + return chosenByPicker || layoutImpl.state.currentOverscrollSpec?.scene == scene } private fun isSharedElementEnabled( @@ -549,6 +563,40 @@ private inline fun <T> computeValue( return idleValue } + if (transition is TransitionState.HasOverscrollProperties) { + val overscroll = layoutImpl.state.currentOverscrollSpec + if (overscroll?.scene == scene.key) { + val elementSpec = overscroll.transformationSpec.transformations(element.key, scene.key) + val propertySpec = transformation(elementSpec) ?: return currentValue() + val overscrollState = checkNotNull(if (scene.key == toScene) toState else fromState) + val targetValue = + propertySpec.transform( + layoutImpl, + scene, + element, + overscrollState, + transition, + idleValue, + ) + + // Make sure we don't read progress if values are the same and we don't need to + // interpolate, so we don't invalidate the phase where this is read. + if (targetValue == idleValue) { + return targetValue + } + + // TODO(b/290184746): Make sure that we don't overflow transformations associated to a + // range. + val directionSign = if (transition.isUpOrLeft) -1 else 1 + val overscrollProgress = transition.progress.let { if (it > 1f) it - 1f else it } + val progress = directionSign * overscrollProgress + val rangeProgress = propertySpec.range?.progress(progress) ?: progress + + // Interpolate between the value at rest and the over scrolled value. + return lerp(idleValue, targetValue, rangeProgress) + } + } + // The element is shared: interpolate between the value in fromScene and the value in toScene. // TODO(b/290184746): Support non linear shared paths as well as a way to make sure that shared // elements follow the finger direction. diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/GestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/GestureHandler.kt deleted file mode 100644 index 58052cd60f39..000000000000 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/GestureHandler.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.android.compose.animation.scene - -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection - -interface DraggableHandler { - fun onDragStarted(startedPosition: Offset, overSlop: Float, pointersDown: Int = 1) - fun onDelta(pixels: Float) - fun onDragStopped(velocity: Float) -} - -interface NestedScrollHandler { - val connection: NestedScrollConnection -} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt index 3ff869b5fdad..05dd5cc09dbf 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.gestures.awaitVerticalTouchSlopOrCancellation import androidx.compose.foundation.gestures.horizontalDrag import androidx.compose.foundation.gestures.verticalDrag import androidx.compose.runtime.Stable -import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.pointer.PointerEvent @@ -33,7 +32,6 @@ import androidx.compose.ui.input.pointer.PointerId import androidx.compose.ui.input.pointer.PointerInputChange import androidx.compose.ui.input.pointer.PointerInputScope import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode -import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.positionChange import androidx.compose.ui.input.pointer.util.VelocityTracker import androidx.compose.ui.input.pointer.util.addPointerInputChange @@ -69,9 +67,7 @@ internal fun Modifier.multiPointerDraggable( orientation: Orientation, enabled: () -> Boolean, startDragImmediately: (startedPosition: Offset) -> Boolean, - onDragStarted: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit, - onDragDelta: (delta: Float) -> Unit, - onDragStopped: (velocity: Float) -> Unit, + onDragStarted: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController, ): Modifier = this.then( MultiPointerDraggableElement( @@ -79,8 +75,6 @@ internal fun Modifier.multiPointerDraggable( enabled, startDragImmediately, onDragStarted, - onDragDelta, - onDragStopped, ) ) @@ -89,9 +83,7 @@ private data class MultiPointerDraggableElement( private val enabled: () -> Boolean, private val startDragImmediately: (startedPosition: Offset) -> Boolean, private val onDragStarted: - (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit, - private val onDragDelta: (Float) -> Unit, - private val onDragStopped: (velocity: Float) -> Unit, + (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController, ) : ModifierNodeElement<MultiPointerDraggableNode>() { override fun create(): MultiPointerDraggableNode = MultiPointerDraggableNode( @@ -99,8 +91,6 @@ private data class MultiPointerDraggableElement( enabled = enabled, startDragImmediately = startDragImmediately, onDragStarted = onDragStarted, - onDragDelta = onDragDelta, - onDragStopped = onDragStopped, ) override fun update(node: MultiPointerDraggableNode) { @@ -108,8 +98,6 @@ private data class MultiPointerDraggableElement( node.enabled = enabled node.startDragImmediately = startDragImmediately node.onDragStarted = onDragStarted - node.onDragDelta = onDragDelta - node.onDragStopped = onDragStopped } } @@ -117,9 +105,8 @@ internal class MultiPointerDraggableNode( orientation: Orientation, enabled: () -> Boolean, var startDragImmediately: (startedPosition: Offset) -> Boolean, - var onDragStarted: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit, - var onDragDelta: (Float) -> Unit, - var onDragStopped: (velocity: Float) -> Unit, + var onDragStarted: + (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController, ) : PointerInputModifierNode, DelegatingNode(), @@ -176,40 +163,33 @@ internal class MultiPointerDraggableNode( return } - val onDragStart: (Offset, Float, Int) -> Unit = { startedPosition, overSlop, pointersDown -> - velocityTracker.resetTracking() - onDragStarted(startedPosition, overSlop, pointersDown) - } - - val onDragCancel: () -> Unit = { onDragStopped(/* velocity= */ 0f) } - - val onDragEnd: () -> Unit = { - val maxFlingVelocity = - currentValueOf(LocalViewConfiguration).maximumFlingVelocity.let { max -> - Velocity(max, max) - } - - val velocity = velocityTracker.calculateVelocity(maxFlingVelocity) - onDragStopped( - when (orientation) { - Orientation.Horizontal -> velocity.x - Orientation.Vertical -> velocity.y - } - ) - } - - val onDrag: (change: PointerInputChange, dragAmount: Float) -> Unit = { change, amount -> - velocityTracker.addPointerInputChange(change) - onDragDelta(amount) - } - detectDragGestures( orientation = orientation, startDragImmediately = startDragImmediately, - onDragStart = onDragStart, - onDragEnd = onDragEnd, - onDragCancel = onDragCancel, - onDrag = onDrag, + onDragStart = { startedPosition, overSlop, pointersDown -> + velocityTracker.resetTracking() + onDragStarted(startedPosition, overSlop, pointersDown) + }, + onDrag = { controller, change, amount -> + velocityTracker.addPointerInputChange(change) + controller.onDrag(amount) + }, + onDragEnd = { controller -> + val viewConfiguration = currentValueOf(LocalViewConfiguration) + val maxVelocity = viewConfiguration.maximumFlingVelocity.let { Velocity(it, it) } + val velocity = velocityTracker.calculateVelocity(maxVelocity) + controller.onStop( + velocity = + when (orientation) { + Orientation.Horizontal -> velocity.x + Orientation.Vertical -> velocity.y + }, + canChangeScene = true, + ) + }, + onDragCancel = { controller -> + controller.onStop(velocity = 0f, canChangeScene = true) + }, ) } } @@ -225,10 +205,10 @@ internal class MultiPointerDraggableNode( private suspend fun PointerInputScope.detectDragGestures( orientation: Orientation, startDragImmediately: (startedPosition: Offset) -> Boolean, - onDragStart: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit, - onDragEnd: () -> Unit, - onDragCancel: () -> Unit, - onDrag: (change: PointerInputChange, dragAmount: Float) -> Unit, + onDragStart: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> DragController, + onDragEnd: (controller: DragController) -> Unit, + onDragCancel: (controller: DragController) -> Unit, + onDrag: (controller: DragController, change: PointerInputChange, dragAmount: Float) -> Unit, ) { awaitEachGesture { val initialDown = awaitFirstDown(requireUnconsumed = false, pass = PointerEventPass.Initial) @@ -282,34 +262,34 @@ private suspend fun PointerInputScope.detectDragGestures( } } - onDragStart(drag.position, overSlop, pressed.size) + val controller = onDragStart(drag.position, overSlop, pressed.size) val successful: Boolean try { - onDrag(drag, overSlop) + onDrag(controller, drag, overSlop) successful = when (orientation) { Orientation.Horizontal -> horizontalDrag(drag.id) { - onDrag(it, it.positionChange().x) + onDrag(controller, it, it.positionChange().x) it.consume() } Orientation.Vertical -> verticalDrag(drag.id) { - onDrag(it, it.positionChange().y) + onDrag(controller, it, it.positionChange().y) it.consume() } } } catch (t: Throwable) { - onDragCancel() + onDragCancel(controller) throw t } if (successful) { - onDragEnd() + onDragEnd(controller) } else { - onDragCancel() + onDragCancel(controller) } } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt index e78f3266d664..5a2f85ad163c 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/NestedScrollToScene.kt @@ -178,7 +178,7 @@ private fun scenePriorityNestedScrollConnection( topOrLeftBehavior: NestedScrollBehavior, bottomOrRightBehavior: NestedScrollBehavior, ) = - SceneNestedScrollHandler( + NestedScrollHandlerImpl( layoutImpl = layoutImpl, orientation = orientation, topOrLeftBehavior = topOrLeftBehavior, diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt index e1f8a0959f6f..1e3842a1de68 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Density @@ -394,36 +395,52 @@ class UserActionResult( /** The scene we should be transitioning to during the [UserAction]. */ val toScene: SceneKey, - /** - * The distance the action takes to animate from 0% to 100%. - * - * If `null`, a default distance will be used that depends on the [UserAction] performed. - */ - val distance: UserActionDistance? = null, - /** The key of the transition that should be used. */ val transitionKey: TransitionKey? = null, -) { - constructor( - toScene: SceneKey, - distance: Dp, - transitionKey: TransitionKey? = null, - ) : this(toScene, FixedDistance(distance), transitionKey) -} +) interface UserActionDistance { /** * Return the **absolute** distance of the user action given the size of the scene we are * animating from and the [orientation]. + * + * Note: This function will be called for each drag event until it returns a value > 0f. This + * for instance allows you to return 0f or a negative value until the first layout pass of a + * scene, so that you can use the size and position of elements in the scene we are + * transitioning to when computing this absolute distance. */ - fun Density.absoluteDistance(fromSceneSize: IntSize, orientation: Orientation): Float + fun UserActionDistanceScope.absoluteDistance( + fromSceneSize: IntSize, + orientation: Orientation + ): Float +} + +interface UserActionDistanceScope : Density { + /** + * Return the *target* size of [this] element in the given [scene], i.e. the size of the element + * when idle, or `null` if the element is not composed and measured in that scene (yet). + */ + fun ElementKey.targetSize(scene: SceneKey): IntSize? + + /** + * Return the *target* offset of [this] element in the given [scene], i.e. the size of the + * element when idle, or `null` if the element is not composed and placed in that scene (yet). + */ + fun ElementKey.targetOffset(scene: SceneKey): Offset? + + /** + * Return the *target* size of [this] scene, i.e. the size of the scene when idle, or `null` if + * the scene was never composed. + */ + fun SceneKey.targetSize(): IntSize? } /** The user action has a fixed [absoluteDistance]. */ -private class FixedDistance(private val distance: Dp) : UserActionDistance { - override fun Density.absoluteDistance(fromSceneSize: IntSize, orientation: Orientation): Float { - return distance.toPx() - } +class FixedDistance(private val distance: Dp) : UserActionDistance { + override fun UserActionDistanceScope.absoluteDistance( + fromSceneSize: IntSize, + orientation: Orientation, + ): Float = distance.toPx() } /** diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt index 08399ff03f63..1670e9cee731 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt @@ -25,8 +25,13 @@ import androidx.compose.runtime.key import androidx.compose.runtime.snapshots.SnapshotStateMap import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ApproachLayoutModifierNode +import androidx.compose.ui.layout.ApproachMeasureScope import androidx.compose.ui.layout.LookaheadScope -import androidx.compose.ui.layout.intermediateLayout +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.layout.MeasureResult +import androidx.compose.ui.node.ModifierNodeElement +import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.IntSize import androidx.compose.ui.util.fastForEach @@ -96,33 +101,42 @@ internal class SceneTransitionLayoutImpl( ?: mutableMapOf<ValueKey, MutableMap<ElementKey?, SnapshotStateMap<SceneKey, *>>>() .also { _sharedValues = it } - private val horizontalGestureHandler: SceneGestureHandler - private val verticalGestureHandler: SceneGestureHandler + // TODO(b/317958526): Lazily allocate scene gesture handlers the first time they are needed. + private val horizontalDraggableHandler: DraggableHandlerImpl + private val verticalDraggableHandler: DraggableHandlerImpl + + private var _userActionDistanceScope: UserActionDistanceScope? = null + internal val userActionDistanceScope: UserActionDistanceScope + get() = + _userActionDistanceScope + ?: UserActionDistanceScopeImpl(layoutImpl = this).also { + _userActionDistanceScope = it + } init { updateScenes(builder) - // SceneGestureHandler must wait for the scenes to be initialized, in order to access the + // DraggableHandlerImpl must wait for the scenes to be initialized, in order to access the // current scene (required for SwipeTransition). - horizontalGestureHandler = - SceneGestureHandler( + horizontalDraggableHandler = + DraggableHandlerImpl( layoutImpl = this, orientation = Orientation.Horizontal, coroutineScope = coroutineScope, ) - verticalGestureHandler = - SceneGestureHandler( + verticalDraggableHandler = + DraggableHandlerImpl( layoutImpl = this, orientation = Orientation.Vertical, coroutineScope = coroutineScope, ) } - internal fun gestureHandler(orientation: Orientation): SceneGestureHandler = + internal fun draggableHandler(orientation: Orientation): DraggableHandlerImpl = when (orientation) { - Orientation.Vertical -> verticalGestureHandler - Orientation.Horizontal -> horizontalGestureHandler + Orientation.Vertical -> verticalDraggableHandler + Orientation.Horizontal -> horizontalDraggableHandler } internal fun scene(key: SceneKey): Scene { @@ -172,46 +186,15 @@ internal class SceneTransitionLayoutImpl( } @Composable - @OptIn(ExperimentalComposeUiApi::class) internal fun Content(modifier: Modifier) { Box( modifier // Handle horizontal and vertical swipes on this layout. // Note: order here is important and will give a slight priority to the vertical // swipes. - .swipeToScene(horizontalGestureHandler) - .swipeToScene(verticalGestureHandler) - // Animate the size of this layout. - .intermediateLayout { measurable, constraints -> - // Measure content normally. - val placeable = measurable.measure(constraints) - - val width: Int - val height: Int - val transition = state.currentTransition - if (transition == null) { - width = placeable.width - height = placeable.height - } else { - // Interpolate the size. - val fromSize = scene(transition.fromScene).targetSize - val toSize = scene(transition.toScene).targetSize - - // Optimization: make sure we don't read state.progress if fromSize == - // toSize to avoid running this code every frame when the layout size does - // not change. - if (fromSize == toSize) { - width = fromSize.width - height = fromSize.height - } else { - val size = lerp(fromSize, toSize, transition.progress) - width = size.width.coerceAtLeast(0) - height = size.height.coerceAtLeast(0) - } - } - - layout(width, height) { placeable.place(0, 0) } - } + .swipeToScene(horizontalDraggableHandler) + .swipeToScene(verticalDraggableHandler) + .then(LayoutElement(layoutImpl = this)) ) { LookaheadScope { val scenesToCompose = @@ -254,3 +237,54 @@ internal class SceneTransitionLayoutImpl( scenes.values.forEach { it.targetSize = size } } } + +private data class LayoutElement(private val layoutImpl: SceneTransitionLayoutImpl) : + ModifierNodeElement<LayoutNode>() { + override fun create(): LayoutNode = LayoutNode(layoutImpl) + + override fun update(node: LayoutNode) { + node.layoutImpl = layoutImpl + } +} + +private class LayoutNode(var layoutImpl: SceneTransitionLayoutImpl) : + Modifier.Node(), ApproachLayoutModifierNode { + override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean { + return layoutImpl.state.currentTransition == null + } + + @ExperimentalComposeUiApi + override fun ApproachMeasureScope.approachMeasure( + measurable: Measurable, + constraints: Constraints, + ): MeasureResult { + // Measure content normally. + val placeable = measurable.measure(constraints) + + val width: Int + val height: Int + val transition = layoutImpl.state.currentTransition + if (transition == null) { + width = placeable.width + height = placeable.height + } else { + // Interpolate the size. + val fromSize = layoutImpl.scene(transition.fromScene).targetSize + val toSize = layoutImpl.scene(transition.toScene).targetSize + + // Optimization: make sure we don't read state.progress if fromSize == + // toSize to avoid running this code every frame when the layout size does + // not change. + if (fromSize == toSize) { + width = fromSize.width + height = fromSize.height + } else { + val size = lerp(fromSize, toSize, transition.progress) + width = size.width.coerceAtLeast(0) + height = size.height.coerceAtLeast(0) + } + } + + return layout(width, height) { placeable.place(0, 0) } + } +} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt index 662f33f3e88b..0fa19bb33818 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt @@ -16,6 +16,7 @@ package com.android.compose.animation.scene +import androidx.compose.foundation.gestures.Orientation import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.SideEffect @@ -221,6 +222,23 @@ sealed interface TransitionState { isTransitioning(from = other, to = scene) } } + + interface HasOverscrollProperties { + /** + * The position of the [TransitionState.Transition.toScene]. + * + * Used to understand the direction of the overscroll. + */ + val isUpOrLeft: Boolean + + /** + * The relative orientation between [TransitionState.Transition.fromScene] and + * [TransitionState.Transition.toScene]. + * + * Used to understand the orientation of the overscroll. + */ + val orientation: Orientation + } } internal abstract class BaseSceneTransitionLayoutState( @@ -237,6 +255,25 @@ internal abstract class BaseSceneTransitionLayoutState( */ internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty + private var fromOverscrollSpec: OverscrollSpecImpl? = null + private var toOverscrollSpec: OverscrollSpecImpl? = null + + /** + * @return the overscroll [OverscrollSpecImpl] if it is defined for the current + * [transitionState] and we are currently over scrolling. + */ + internal val currentOverscrollSpec: OverscrollSpecImpl? + get() { + val transition = currentTransition ?: return null + if (transition !is TransitionState.HasOverscrollProperties) return null + val progress = transition.progress + return when { + progress < 0f -> fromOverscrollSpec + progress > 1f -> toOverscrollSpec + else -> null + } + } + private val activeTransitionLinks = mutableMapOf<StateLink, LinkedTransition>() /** Whether we can transition to the given [scene]. */ @@ -266,10 +303,13 @@ internal abstract class BaseSceneTransitionLayoutState( transitionKey: TransitionKey?, ) { // Compute the [TransformationSpec] when the transition starts. + val fromScene = transition.fromScene + val toScene = transition.toScene + val orientation = (transition as? TransitionState.HasOverscrollProperties)?.orientation transformationSpec = - transitions - .transitionSpec(transition.fromScene, transition.toScene, key = transitionKey) - .transformationSpec() + transitions.transitionSpec(fromScene, toScene, key = transitionKey).transformationSpec() + fromOverscrollSpec = orientation?.let { transitions.overscrollSpec(fromScene, it) } + toOverscrollSpec = orientation?.let { transitions.overscrollSpec(toScene, it) } cancelActiveTransitionLinks() setupTransitionLinks(transition) transitionState = transition diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt index b8f9359463de..2dd41cd329a2 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt @@ -21,6 +21,7 @@ import androidx.compose.animation.core.Spring import androidx.compose.animation.core.SpringSpec import androidx.compose.animation.core.snap import androidx.compose.animation.core.spring +import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.util.fastForEach @@ -41,18 +42,22 @@ class SceneTransitions internal constructor( internal val defaultSwipeSpec: SpringSpec<Float>, internal val transitionSpecs: List<TransitionSpecImpl>, + internal val overscrollSpecs: List<OverscrollSpecImpl>, ) { - private val cache = + private val transitionCache = mutableMapOf< SceneKey, MutableMap<SceneKey, MutableMap<TransitionKey?, TransitionSpecImpl>> >() + private val overscrollCache = + mutableMapOf<SceneKey, MutableMap<Orientation, OverscrollSpecImpl?>>() + internal fun transitionSpec( from: SceneKey, to: SceneKey, key: TransitionKey?, ): TransitionSpecImpl { - return cache + return transitionCache .getOrPut(from) { mutableMapOf() } .getOrPut(to) { mutableMapOf() } .getOrPut(key) { findSpec(from, to, key) } @@ -105,6 +110,28 @@ internal constructor( private fun defaultTransition(from: SceneKey, to: SceneKey) = TransitionSpecImpl(key = null, from, to, TransformationSpec.EmptyProvider) + internal fun overscrollSpec(scene: SceneKey, orientation: Orientation): OverscrollSpecImpl? = + overscrollCache + .getOrPut(scene) { mutableMapOf() } + .getOrPut(orientation) { overscroll(scene, orientation) { it.scene == scene } } + + private fun overscroll( + scene: SceneKey, + orientation: Orientation, + filter: (OverscrollSpecImpl) -> Boolean, + ): OverscrollSpecImpl? { + var match: OverscrollSpecImpl? = null + overscrollSpecs.fastForEach { spec -> + if (spec.orientation == orientation && filter(spec)) { + if (match != null) { + error("Found multiple transition specs for transition $scene") + } + match = spec + } + } + return match + } + companion object { internal val DefaultSwipeSpec = spring( @@ -112,7 +139,12 @@ internal constructor( visibilityThreshold = OffsetVisibilityThreshold, ) - val Empty = SceneTransitions(DefaultSwipeSpec, transitionSpecs = emptyList()) + val Empty = + SceneTransitions( + defaultSwipeSpec = DefaultSwipeSpec, + transitionSpecs = emptyList(), + overscrollSpecs = emptyList(), + ) } } @@ -139,7 +171,7 @@ interface TransitionSpec { */ fun reversed(): TransitionSpec - /* + /** * The [TransformationSpec] associated to this [TransitionSpec]. * * Note that this is called once every a transition associated to this [TransitionSpec] is @@ -163,6 +195,14 @@ interface TransformationSpec { */ val swipeSpec: SpringSpec<Float>? + /** + * The distance it takes for this transition to animate from 0% to 100% when it is driven by a + * [UserAction]. + * + * If `null`, a default distance will be used that depends on the [UserAction] performed. + */ + val distance: UserActionDistance? + /** The list of [Transformation] applied to elements during this transition. */ val transformations: List<Transformation> @@ -171,6 +211,7 @@ interface TransformationSpec { TransformationSpecImpl( progressSpec = snap(), swipeSpec = null, + distance = null, transformations = emptyList(), ) internal val EmptyProvider = { Empty } @@ -193,6 +234,7 @@ internal class TransitionSpecImpl( TransformationSpecImpl( progressSpec = reverse.progressSpec, swipeSpec = reverse.swipeSpec, + distance = reverse.distance, transformations = reverse.transformations.map { it.reversed() } ) } @@ -202,6 +244,24 @@ internal class TransitionSpecImpl( override fun transformationSpec(): TransformationSpecImpl = this.transformationSpec.invoke() } +/** The definition of the overscroll behavior of the [scene]. */ +interface OverscrollSpec { + /** The scene we are over scrolling. */ + val scene: SceneKey + + /** The orientation of this [OverscrollSpec]. */ + val orientation: Orientation + + /** The [TransformationSpec] associated to this [OverscrollSpec]. */ + val transformationSpec: TransformationSpec +} + +internal class OverscrollSpecImpl( + override val scene: SceneKey, + override val orientation: Orientation, + override val transformationSpec: TransformationSpecImpl, +) : OverscrollSpec + /** * An implementation of [TransformationSpec] that allows the quick retrieval of an element * [ElementTransformations]. @@ -209,6 +269,7 @@ internal class TransitionSpecImpl( internal class TransformationSpecImpl( override val progressSpec: AnimationSpec<Float>, override val swipeSpec: SpringSpec<Float>?, + override val distance: UserActionDistance?, override val transformations: List<Transformation>, ) : TransformationSpec { private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>() diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt index 61f497818c89..b618369c2369 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt @@ -31,39 +31,39 @@ import androidx.compose.ui.unit.IntSize * Configures the swipeable behavior of a [SceneTransitionLayout] depending on the current state. */ @Stable -internal fun Modifier.swipeToScene(gestureHandler: SceneGestureHandler): Modifier { - return this.then(SwipeToSceneElement(gestureHandler)) +internal fun Modifier.swipeToScene(draggableHandler: DraggableHandlerImpl): Modifier { + return this.then(SwipeToSceneElement(draggableHandler)) } private data class SwipeToSceneElement( - val gestureHandler: SceneGestureHandler, + val draggableHandler: DraggableHandlerImpl, ) : ModifierNodeElement<SwipeToSceneNode>() { - override fun create(): SwipeToSceneNode = SwipeToSceneNode(gestureHandler) + override fun create(): SwipeToSceneNode = SwipeToSceneNode(draggableHandler) override fun update(node: SwipeToSceneNode) { - node.gestureHandler = gestureHandler + node.draggableHandler = draggableHandler } } private class SwipeToSceneNode( - gestureHandler: SceneGestureHandler, + draggableHandler: DraggableHandlerImpl, ) : DelegatingNode(), PointerInputModifierNode { private val delegate = delegate( MultiPointerDraggableNode( - orientation = gestureHandler.orientation, + orientation = draggableHandler.orientation, enabled = ::enabled, startDragImmediately = ::startDragImmediately, - onDragStarted = gestureHandler.draggable::onDragStarted, - onDragDelta = gestureHandler.draggable::onDelta, - onDragStopped = gestureHandler.draggable::onDragStopped, + onDragStarted = draggableHandler::onDragStarted, ) ) - var gestureHandler: SceneGestureHandler = gestureHandler + private var _draggableHandler = draggableHandler + var draggableHandler: DraggableHandlerImpl + get() = _draggableHandler set(value) { - if (value != field) { - field = value + if (_draggableHandler != value) { + _draggableHandler = value // Make sure to update the delegate orientation. Note that this will automatically // reset the underlying pointer input handler, so previous gestures will be @@ -81,12 +81,12 @@ private class SwipeToSceneNode( override fun onCancelPointerInput() = delegate.onCancelPointerInput() private fun enabled(): Boolean { - return gestureHandler.isDrivingTransition || - currentScene().shouldEnableSwipes(gestureHandler.orientation) + return draggableHandler.isDrivingTransition || + currentScene().shouldEnableSwipes(delegate.orientation) } private fun currentScene(): Scene { - val layoutImpl = gestureHandler.layoutImpl + val layoutImpl = draggableHandler.layoutImpl return layoutImpl.scene(layoutImpl.state.transitionState.currentScene) } @@ -98,12 +98,12 @@ private class SwipeToSceneNode( private fun startDragImmediately(startedPosition: Offset): Boolean { // Immediately start the drag if the user can't swipe in the other direction and the gesture // handler can intercept it. - return !canOppositeSwipe() && gestureHandler.shouldImmediatelyIntercept(startedPosition) + return !canOppositeSwipe() && draggableHandler.shouldImmediatelyIntercept(startedPosition) } private fun canOppositeSwipe(): Boolean { val oppositeOrientation = - when (gestureHandler.orientation) { + when (draggableHandler.orientation) { Orientation.Vertical -> Orientation.Horizontal Orientation.Horizontal -> Orientation.Vertical } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt index d93911d2de42..bc52a28279dc 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt @@ -18,6 +18,7 @@ package com.android.compose.animation.scene import androidx.compose.animation.core.AnimationSpec import androidx.compose.animation.core.SpringSpec +import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -72,23 +73,30 @@ interface SceneTransitionsBuilder { key: TransitionKey? = null, builder: TransitionBuilder.() -> Unit = {}, ): TransitionSpec -} -@TransitionDsl -interface TransitionBuilder : PropertyTransformationBuilder { /** - * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when - * the transition is triggered (i.e. it is not gesture-based). + * Define the animation to be played when the [scene] is overscrolled in the given + * [orientation]. + * + * The overscroll animation always starts from a progress of 0f, and reaches 1f when moving the + * [distance] down/right, -1f when moving in the opposite direction. */ - var spec: AnimationSpec<Float> + fun overscroll( + scene: SceneKey, + orientation: Orientation, + builder: OverscrollBuilder.() -> Unit = {}, + ): OverscrollSpec +} +@TransitionDsl +interface OverscrollBuilder : PropertyTransformationBuilder { /** - * The [SpringSpec] used to animate the associated transition progress when the transition was - * started by a swipe and is now animating back to a scene because the user lifted their finger. + * The distance it takes for this transition to animate from 0% to 100% when it is driven by a + * [UserAction]. * - * If `null`, then the [SceneTransitionsBuilder.defaultSwipeSpec] will be used. + * If `null`, a default distance will be used that depends on the [UserAction] performed. */ - var swipeSpec: SpringSpec<Float>? + var distance: UserActionDistance? /** * Define a progress-based range for the transformations inside [builder]. @@ -109,6 +117,23 @@ interface TransitionBuilder : PropertyTransformationBuilder { end: Float? = null, builder: PropertyTransformationBuilder.() -> Unit, ) +} + +@TransitionDsl +interface TransitionBuilder : OverscrollBuilder, PropertyTransformationBuilder { + /** + * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when + * the transition is triggered (i.e. it is not gesture-based). + */ + var spec: AnimationSpec<Float> + + /** + * The [SpringSpec] used to animate the associated transition progress when the transition was + * started by a swipe and is now animating back to a scene because the user lifted their finger. + * + * If `null`, then the [SceneTransitionsBuilder.defaultSwipeSpec] will be used. + */ + var swipeSpec: SpringSpec<Float>? /** * Define a timestamp-based range for the transformations inside [builder]. diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt index 9b16d46bfcc8..65e8ea5cc341 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt @@ -21,7 +21,9 @@ import androidx.compose.animation.core.DurationBasedAnimationSpec import androidx.compose.animation.core.Spring import androidx.compose.animation.core.SpringSpec import androidx.compose.animation.core.VectorConverter +import androidx.compose.animation.core.snap import androidx.compose.animation.core.spring +import androidx.compose.foundation.gestures.Orientation import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Dp import com.android.compose.animation.scene.transformation.AnchoredSize @@ -41,13 +43,18 @@ internal fun transitionsImpl( builder: SceneTransitionsBuilder.() -> Unit, ): SceneTransitions { val impl = SceneTransitionsBuilderImpl().apply(builder) - return SceneTransitions(impl.defaultSwipeSpec, impl.transitionSpecs) + return SceneTransitions( + impl.defaultSwipeSpec, + impl.transitionSpecs, + impl.transitionOverscrollSpecs + ) } private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { override var defaultSwipeSpec: SpringSpec<Float> = SceneTransitions.DefaultSwipeSpec val transitionSpecs = mutableListOf<TransitionSpecImpl>() + val transitionOverscrollSpecs = mutableListOf<OverscrollSpecImpl>() override fun to( to: SceneKey, @@ -66,6 +73,25 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { return transition(from = from, to = to, key = key, builder) } + override fun overscroll( + scene: SceneKey, + orientation: Orientation, + builder: OverscrollBuilder.() -> Unit + ): OverscrollSpec { + fun transformationSpec(): TransformationSpecImpl { + val impl = OverscrollBuilderImpl().apply(builder) + return TransformationSpecImpl( + progressSpec = snap(), + swipeSpec = null, + distance = impl.distance, + transformations = impl.transformations, + ) + } + val spec = OverscrollSpecImpl(scene, orientation, transformationSpec()) + transitionOverscrollSpecs.add(spec) + return spec + } + private fun transition( from: SceneKey?, to: SceneKey?, @@ -77,6 +103,7 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { return TransformationSpecImpl( progressSpec = impl.spec, swipeSpec = impl.swipeSpec, + distance = impl.distance, transformations = impl.transformations, ) } @@ -87,27 +114,11 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { } } -internal class TransitionBuilderImpl : TransitionBuilder { +internal open class OverscrollBuilderImpl : OverscrollBuilder { val transformations = mutableListOf<Transformation>() - override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow) - override var swipeSpec: SpringSpec<Float>? = null - private var range: TransformationRange? = null - private var reversed = false - private val durationMillis: Int by lazy { - val spec = spec - if (spec !is DurationBasedAnimationSpec) { - error("timestampRange {} can only be used with a DurationBasedAnimationSpec") - } - - spec.vectorize(Float.VectorConverter).durationMillis - } - - override fun reversed(builder: TransitionBuilder.() -> Unit) { - reversed = true - builder() - reversed = false - } + protected var reversed = false + override var distance: UserActionDistance? = null override fun fractionRange( start: Float?, @@ -119,28 +130,6 @@ internal class TransitionBuilderImpl : TransitionBuilder { range = null } - override fun sharedElement(matcher: ElementMatcher, enabled: Boolean) { - transformations.add(SharedElementTransformation(matcher, enabled)) - } - - override fun timestampRange( - startMillis: Int?, - endMillis: Int?, - builder: PropertyTransformationBuilder.() -> Unit - ) { - if (startMillis != null && (startMillis < 0 || startMillis > durationMillis)) { - error("invalid start value: startMillis=$startMillis durationMillis=$durationMillis") - } - - if (endMillis != null && (endMillis < 0 || endMillis > durationMillis)) { - error("invalid end value: endMillis=$startMillis durationMillis=$durationMillis") - } - - val start = startMillis?.let { it.toFloat() / durationMillis } - val end = endMillis?.let { it.toFloat() / durationMillis } - fractionRange(start, end, builder) - } - private fun transformation(transformation: PropertyTransformation<*>) { val transformation = if (range != null) { @@ -195,3 +184,45 @@ internal class TransitionBuilderImpl : TransitionBuilder { transformation(AnchoredSize(matcher, anchor, anchorWidth, anchorHeight)) } } + +internal class TransitionBuilderImpl : OverscrollBuilderImpl(), TransitionBuilder { + override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow) + override var swipeSpec: SpringSpec<Float>? = null + override var distance: UserActionDistance? = null + private val durationMillis: Int by lazy { + val spec = spec + if (spec !is DurationBasedAnimationSpec) { + error("timestampRange {} can only be used with a DurationBasedAnimationSpec") + } + + spec.vectorize(Float.VectorConverter).durationMillis + } + + override fun reversed(builder: TransitionBuilder.() -> Unit) { + reversed = true + builder() + reversed = false + } + + override fun sharedElement(matcher: ElementMatcher, enabled: Boolean) { + transformations.add(SharedElementTransformation(matcher, enabled)) + } + + override fun timestampRange( + startMillis: Int?, + endMillis: Int?, + builder: PropertyTransformationBuilder.() -> Unit + ) { + if (startMillis != null && (startMillis < 0 || startMillis > durationMillis)) { + error("invalid start value: startMillis=$startMillis durationMillis=$durationMillis") + } + + if (endMillis != null && (endMillis < 0 || endMillis > durationMillis)) { + error("invalid end value: endMillis=$startMillis durationMillis=$durationMillis") + } + + val start = startMillis?.let { it.toFloat() / durationMillis } + val end = endMillis?.let { it.toFloat() / durationMillis } + fractionRange(start, end, builder) + } +} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt new file mode 100644 index 000000000000..228d19f09cff --- /dev/null +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.animation.scene + +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.unit.IntSize + +internal class UserActionDistanceScopeImpl( + private val layoutImpl: SceneTransitionLayoutImpl, +) : UserActionDistanceScope { + override val density: Float + get() = layoutImpl.density.density + + override val fontScale: Float + get() = layoutImpl.density.fontScale + + override fun ElementKey.targetSize(scene: SceneKey): IntSize? { + return layoutImpl.elements[this]?.sceneStates?.get(scene)?.targetSize.takeIf { + it != Element.SizeUnspecified + } + } + + override fun ElementKey.targetOffset(scene: SceneKey): Offset? { + return layoutImpl.elements[this]?.sceneStates?.get(scene)?.targetOffset.takeIf { + it != Offset.Unspecified + } + } + + override fun SceneKey.targetSize(): IntSize? { + return layoutImpl.scenes[this]?.targetSize.takeIf { it != IntSize.Zero } + } +} diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt index fe53d5b45420..eb9b4280aacb 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt @@ -47,12 +47,12 @@ private const val SCREEN_SIZE = 100f private val LAYOUT_SIZE = IntSize(SCREEN_SIZE.toInt(), SCREEN_SIZE.toInt()) @RunWith(AndroidJUnit4::class) -class SceneGestureHandlerTest { +class DraggableHandlerTest { private class TestGestureScope( private val testScope: MonotonicClockTestScope, ) { var canChangeScene: (SceneKey) -> Boolean = { true } - private val layoutState = + val layoutState = MutableSceneTransitionLayoutStateImpl( SceneA, EmptyTestTransitions, @@ -99,19 +99,19 @@ class SceneGestureHandlerTest { ) .apply { setScenesTargetSizeForTest(LAYOUT_SIZE) } - val sceneGestureHandler = layoutImpl.gestureHandler(Orientation.Vertical) - val horizontalSceneGestureHandler = layoutImpl.gestureHandler(Orientation.Horizontal) + val draggableHandler = layoutImpl.draggableHandler(Orientation.Vertical) + val horizontalDraggableHandler = layoutImpl.draggableHandler(Orientation.Horizontal) fun nestedScrollConnection(nestedScrollBehavior: NestedScrollBehavior) = - SceneNestedScrollHandler( + NestedScrollHandlerImpl( layoutImpl = layoutImpl, - orientation = sceneGestureHandler.orientation, + orientation = draggableHandler.orientation, topOrLeftBehavior = nestedScrollBehavior, bottomOrRightBehavior = nestedScrollBehavior, ) .connection - val velocityThreshold = sceneGestureHandler.velocityThreshold + val velocityThreshold = draggableHandler.velocityThreshold fun down(fractionOfScreen: Float) = if (fractionOfScreen < 0f) error("use up()") else SCREEN_SIZE * fractionOfScreen @@ -190,20 +190,18 @@ class SceneGestureHandlerTest { fun onDragStarted( startedPosition: Offset = Offset.Zero, overSlop: Float, - pointersDown: Int = 1 - ) { + pointersDown: Int = 1, + ): DragController { // overSlop should be 0f only if the drag gesture starts with startDragImmediately if (overSlop == 0f) error("Consider using onDragStartedImmediately()") - onDragStarted(sceneGestureHandler.draggable, startedPosition, overSlop, pointersDown) + return onDragStarted(draggableHandler, startedPosition, overSlop, pointersDown) } - fun onDragStartedImmediately(startedPosition: Offset = Offset.Zero, pointersDown: Int = 1) { - onDragStarted( - sceneGestureHandler.draggable, - startedPosition, - overSlop = 0f, - pointersDown - ) + fun onDragStartedImmediately( + startedPosition: Offset = Offset.Zero, + pointersDown: Int = 1, + ): DragController { + return onDragStarted(draggableHandler, startedPosition, overSlop = 0f, pointersDown) } fun onDragStarted( @@ -211,24 +209,26 @@ class SceneGestureHandlerTest { startedPosition: Offset = Offset.Zero, overSlop: Float = 0f, pointersDown: Int = 1 - ) { - draggableHandler.onDragStarted( - startedPosition = startedPosition, - overSlop = overSlop, - pointersDown = pointersDown, - ) + ): DragController { + val dragController = + draggableHandler.onDragStarted( + startedPosition = startedPosition, + overSlop = overSlop, + pointersDown = pointersDown, + ) // MultiPointerDraggable will always call onDelta with the initial overSlop right after - onDelta(pixels = overSlop) + dragController.onDragDelta(pixels = overSlop) + + return dragController } - fun onDelta(pixels: Float) { - sceneGestureHandler.draggable.onDelta(pixels = pixels) + fun DragController.onDragDelta(pixels: Float) { + onDrag(delta = pixels) } - fun onDragStopped(velocity: Float) { - sceneGestureHandler.draggable.onDragStopped(velocity = velocity) - runCurrent() + fun DragController.onDragStopped(velocity: Float, canChangeScene: Boolean = true) { + onStop(velocity, canChangeScene) } fun NestedScrollConnection.scroll( @@ -281,20 +281,20 @@ class SceneGestureHandlerTest { @Test fun afterSceneTransitionIsStarted_interceptDragEvents() = runGestureTest { - onDragStarted(overSlop = down(fractionOfScreen = 0.1f)) + val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.1f)) assertTransition(currentScene = SceneA) assertThat(progress).isEqualTo(0.1f) - onDelta(pixels = down(fractionOfScreen = 0.1f)) + dragController.onDragDelta(pixels = down(fractionOfScreen = 0.1f)) assertThat(progress).isEqualTo(0.2f) } @Test fun onDragStoppedAfterDrag_velocityLowerThanThreshold_remainSameScene() = runGestureTest { - onDragStarted(overSlop = down(fractionOfScreen = 0.1f)) + val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.1f)) assertTransition(currentScene = SceneA) - onDragStopped(velocity = velocityThreshold - 0.01f) + dragController.onDragStopped(velocity = velocityThreshold - 0.01f) assertTransition(currentScene = SceneA) // wait for the stop animation @@ -304,10 +304,10 @@ class SceneGestureHandlerTest { @Test fun onDragStoppedAfterDrag_velocityAtLeastThreshold_goToNextScene() = runGestureTest { - onDragStarted(overSlop = down(fractionOfScreen = 0.1f)) + val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.1f)) assertTransition(currentScene = SceneA) - onDragStopped(velocity = velocityThreshold) + dragController.onDragStopped(velocity = velocityThreshold) assertTransition(currentScene = SceneC) // wait for the stop animation @@ -317,10 +317,10 @@ class SceneGestureHandlerTest { @Test fun onDragStoppedAfterStarted_returnToIdle() = runGestureTest { - onDragStarted(overSlop = down(fractionOfScreen = 0.1f)) + val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.1f)) assertTransition(currentScene = SceneA) - onDragStopped(velocity = 0f) + dragController.onDragStopped(velocity = 0f) advanceUntilIdle() assertIdle(currentScene = SceneA) } @@ -328,7 +328,7 @@ class SceneGestureHandlerTest { @Test fun onDragReversedDirection_changeToScene() = runGestureTest { // Drag A -> B with progress 0.6 - onDragStarted(overSlop = -60f) + val dragController = onDragStarted(overSlop = -60f) assertTransition( currentScene = SceneA, fromScene = SceneA, @@ -337,7 +337,7 @@ class SceneGestureHandlerTest { ) // Reverse direction such that A -> C now with 0.4 - onDelta(pixels = 100f) + dragController.onDragDelta(pixels = 100f) assertTransition( currentScene = SceneA, fromScene = SceneA, @@ -346,7 +346,7 @@ class SceneGestureHandlerTest { ) // After the drag stopped scene C should be committed - onDragStopped(velocity = velocityThreshold) + dragController.onDragStopped(velocity = velocityThreshold) assertTransition(currentScene = SceneC, fromScene = SceneA, toScene = SceneC) // wait for the stop animation @@ -356,8 +356,6 @@ class SceneGestureHandlerTest { @Test fun onDragStartedWithoutActionsInBothDirections_stayIdle() = runGestureTest { - val horizontalDraggableHandler = horizontalSceneGestureHandler.draggable - onDragStarted(horizontalDraggableHandler, overSlop = up(fractionOfScreen = 0.3f)) assertIdle(currentScene = SceneA) @@ -370,7 +368,7 @@ class SceneGestureHandlerTest { navigateToSceneC() // We are on SceneC which has no action in Down direction - onDragStarted(overSlop = 10f) + val dragController = onDragStarted(overSlop = 10f) assertTransition( currentScene = SceneC, fromScene = SceneC, @@ -379,7 +377,7 @@ class SceneGestureHandlerTest { ) // Reverse drag direction, it will consume the previous drag - onDelta(pixels = -10f) + dragController.onDragDelta(pixels = -10f) assertTransition( currentScene = SceneC, fromScene = SceneC, @@ -388,7 +386,7 @@ class SceneGestureHandlerTest { ) // Continue reverse drag direction, it should record progress to Scene B - onDelta(pixels = -10f) + dragController.onDragDelta(pixels = -10f) assertTransition( currentScene = SceneC, fromScene = SceneC, @@ -416,14 +414,14 @@ class SceneGestureHandlerTest { @Test fun onDragToExactlyZero_toSceneIsSet() = runGestureTest { - onDragStarted(overSlop = down(fractionOfScreen = 0.3f)) + val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.3f)) assertTransition( currentScene = SceneA, fromScene = SceneA, toScene = SceneC, progress = 0.3f ) - onDelta(pixels = up(fractionOfScreen = 0.3f)) + dragController.onDragDelta(pixels = up(fractionOfScreen = 0.3f)) assertTransition( currentScene = SceneA, fromScene = SceneA, @@ -434,8 +432,8 @@ class SceneGestureHandlerTest { private fun TestGestureScope.navigateToSceneC() { assertIdle(currentScene = SceneA) - onDragStarted(overSlop = down(fractionOfScreen = 1f)) - onDragStopped(velocity = 0f) + val dragController = onDragStarted(overSlop = down(fractionOfScreen = 1f)) + dragController.onDragStopped(velocity = 0f) advanceUntilIdle() assertIdle(currentScene = SceneC) } @@ -443,7 +441,7 @@ class SceneGestureHandlerTest { @Test fun onAccelaratedScroll_scrollToThirdScene() = runGestureTest { // Drag A -> B with progress 0.2 - onDragStarted(overSlop = up(fractionOfScreen = 0.2f)) + val dragController1 = onDragStarted(overSlop = up(fractionOfScreen = 0.2f)) assertTransition( currentScene = SceneA, fromScene = SceneA, @@ -452,13 +450,13 @@ class SceneGestureHandlerTest { ) // Start animation A -> B with progress 0.2 -> 1.0 - onDragStopped(velocity = -velocityThreshold) + dragController1.onDragStopped(velocity = -velocityThreshold) assertTransition(currentScene = SceneB, fromScene = SceneA, toScene = SceneB) // While at A -> B do a 100% screen drag (progress 1.2). This should go past B and change // the transition to B -> C with progress 0.2 - onDragStartedImmediately() - onDelta(pixels = up(fractionOfScreen = 1f)) + val dragController2 = onDragStartedImmediately() + dragController2.onDragDelta(pixels = up(fractionOfScreen = 1f)) assertTransition( currentScene = SceneB, fromScene = SceneB, @@ -467,7 +465,7 @@ class SceneGestureHandlerTest { ) // After the drag stopped scene C should be committed - onDragStopped(velocity = -velocityThreshold) + dragController2.onDragStopped(velocity = -velocityThreshold) assertTransition(currentScene = SceneC, fromScene = SceneB, toScene = SceneC) // wait for the stop animation @@ -477,9 +475,9 @@ class SceneGestureHandlerTest { @Test fun onAccelaratedScrollBothTargetsBecomeNull_settlesToIdle() = runGestureTest { - onDragStarted(overSlop = up(fractionOfScreen = 0.2f)) - onDelta(pixels = up(fractionOfScreen = 0.2f)) - onDragStopped(velocity = -velocityThreshold) + val dragController1 = onDragStarted(overSlop = up(fractionOfScreen = 0.2f)) + dragController1.onDragDelta(pixels = up(fractionOfScreen = 0.2f)) + dragController1.onDragStopped(velocity = -velocityThreshold) assertTransition(currentScene = SceneB, fromScene = SceneA, toScene = SceneB) mutableUserActionsA.remove(Swipe.Up) @@ -488,34 +486,34 @@ class SceneGestureHandlerTest { mutableUserActionsB.remove(Swipe.Down) // start accelaratedScroll and scroll over to B -> null - onDragStartedImmediately() - onDelta(pixels = up(fractionOfScreen = 0.5f)) - onDelta(pixels = up(fractionOfScreen = 0.5f)) + val dragController2 = onDragStartedImmediately() + dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f)) + dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f)) // here onDragStopped is already triggered, but subsequent onDelta/onDragStopped calls may // still be called. Make sure that they don't crash or change the scene - onDelta(pixels = up(fractionOfScreen = 0.5f)) - onDragStopped(velocity = 0f) + dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f)) + dragController2.onDragStopped(velocity = 0f) advanceUntilIdle() assertIdle(SceneB) // These events can still come in after the animation has settled - onDelta(pixels = up(fractionOfScreen = 0.5f)) - onDragStopped(velocity = 0f) + dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f)) + dragController2.onDragStopped(velocity = 0f) assertIdle(SceneB) } @Test fun onDragTargetsChanged_targetStaysTheSame() = runGestureTest { - onDragStarted(overSlop = up(fractionOfScreen = 0.1f)) + val dragController1 = onDragStarted(overSlop = up(fractionOfScreen = 0.1f)) assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.1f) mutableUserActionsA[Swipe.Up] = UserActionResult(SceneC) - onDelta(pixels = up(fractionOfScreen = 0.1f)) + dragController1.onDragDelta(pixels = up(fractionOfScreen = 0.1f)) // target stays B even though UserActions changed assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.2f) - onDragStopped(velocity = down(fractionOfScreen = 0.1f)) + dragController1.onDragStopped(velocity = down(fractionOfScreen = 0.1f)) advanceUntilIdle() // now target changed to C for new drag @@ -525,25 +523,26 @@ class SceneGestureHandlerTest { @Test fun onDragTargetsChanged_targetsChangeWhenStartingNewDrag() = runGestureTest { - onDragStarted(overSlop = up(fractionOfScreen = 0.1f)) + val dragController1 = onDragStarted(overSlop = up(fractionOfScreen = 0.1f)) assertTransition(fromScene = SceneA, toScene = SceneB, progress = 0.1f) mutableUserActionsA[Swipe.Up] = UserActionResult(SceneC) - onDelta(pixels = up(fractionOfScreen = 0.1f)) - onDragStopped(velocity = down(fractionOfScreen = 0.1f)) + dragController1.onDragDelta(pixels = up(fractionOfScreen = 0.1f)) + dragController1.onDragStopped(velocity = down(fractionOfScreen = 0.1f)) // now target changed to C for new drag that started before previous drag settled to Idle - onDragStartedImmediately() - onDelta(pixels = up(fractionOfScreen = 0.1f)) + val dragController2 = onDragStartedImmediately() + dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.1f)) assertTransition(fromScene = SceneA, toScene = SceneC, progress = 0.3f) } @Test fun startGestureDuringAnimatingOffset_shouldImmediatelyStopTheAnimation() = runGestureTest { - onDragStarted(overSlop = down(fractionOfScreen = 0.1f)) + val dragController = onDragStarted(overSlop = down(fractionOfScreen = 0.1f)) assertTransition(currentScene = SceneA) - onDragStopped(velocity = velocityThreshold) + dragController.onDragStopped(velocity = velocityThreshold) + runCurrent() assertTransition(currentScene = SceneC) assertThat(isUserInputOngoing).isFalse() @@ -632,7 +631,7 @@ class SceneGestureHandlerTest { // stop scene transition (start the "stop animation") nestedScroll.preFling(available = Velocity.Zero) - // a pre scroll event, that could be intercepted by SceneGestureHandler + // a pre scroll event, that could be intercepted by DraggableHandlerImpl nestedScroll.onPreScroll( available = Offset(0f, secondScroll), source = NestedScrollSource.Drag @@ -801,18 +800,6 @@ class SceneGestureHandlerTest { } @Test - fun beforeDraggableStart_drag_shouldBeIgnored() = runGestureTest { - onDelta(pixels = down(fractionOfScreen = 0.1f)) - assertIdle(currentScene = SceneA) - } - - @Test - fun beforeDraggableStart_stop_shouldBeIgnored() = runGestureTest { - onDragStopped(velocity = velocityThreshold) - assertIdle(currentScene = SceneA) - } - - @Test fun beforeNestedScrollStart_stop_shouldBeIgnored() = runGestureTest { val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview) nestedScroll.preFling(available = Velocity(0f, velocityThreshold)) @@ -826,7 +813,7 @@ class SceneGestureHandlerTest { val offsetY10 = downOffset(fractionOfScreen = 0.1f) // Start a drag and then stop it, given that - onDragStarted(overSlop = up(0.1f)) + val dragController = onDragStarted(overSlop = up(0.1f)) assertTransition(currentScene = SceneA) assertThat(progress).isEqualTo(0.1f) @@ -836,7 +823,7 @@ class SceneGestureHandlerTest { assertThat(progress).isEqualTo(0.2f) // this should be ignored, we are scrolling now! - onDragStopped(-velocityThreshold) + dragController.onDragStopped(-velocityThreshold) assertTransition(currentScene = SceneA) nestedScroll.scroll(available = -offsetY10) @@ -865,6 +852,7 @@ class SceneGestureHandlerTest { currentScene = SceneC, fromScene = SceneC, toScene = SceneB, + progress = 0.1f, isUserInputOngoing = true, ) @@ -873,18 +861,25 @@ class SceneGestureHandlerTest { // During the current gesture, start a new gesture, still in the middle of the screen. We // should intercept it. Because it is intercepted, the overSlop passed to onDragStarted() // should be 0f. - assertThat(sceneGestureHandler.shouldImmediatelyIntercept(middle)).isTrue() + assertThat(draggableHandler.shouldImmediatelyIntercept(middle)).isTrue() onDragStartedImmediately(startedPosition = middle) // We should have intercepted the transition, so the transition should be the same object. - assertTransition(currentScene = SceneC, fromScene = SceneC, toScene = SceneB) - assertThat(transitionState).isSameInstanceAs(firstTransition) + assertTransition( + currentScene = SceneC, + fromScene = SceneC, + toScene = SceneB, + progress = 0.1f, + isUserInputOngoing = true, + ) + // We should have a new transition + assertThat(transitionState).isNotSameInstanceAs(firstTransition) // Start a new gesture from the bottom of the screen. Because swiping up from the bottom of // C leads to scene A (and not B), the previous transitions is *not* intercepted and we // instead animate from C to A. val bottom = Offset(SCREEN_SIZE / 2, SCREEN_SIZE) - assertThat(sceneGestureHandler.shouldImmediatelyIntercept(bottom)).isFalse() + assertThat(draggableHandler.shouldImmediatelyIntercept(bottom)).isFalse() onDragStarted(startedPosition = bottom, overSlop = up(0.1f)) assertTransition( @@ -901,12 +896,12 @@ class SceneGestureHandlerTest { assertIdle(SceneA) // Swipe up to scene B. - onDragStarted(overSlop = up(0.1f)) + val dragController = onDragStarted(overSlop = up(0.1f)) assertTransition(currentScene = SceneA, fromScene = SceneA, toScene = SceneB) // Block the transition when the user release their finger. canChangeScene = { false } - onDragStopped(velocity = -velocityThreshold) + dragController.onDragStopped(velocity = -velocityThreshold) advanceUntilIdle() assertIdle(SceneA) } @@ -916,20 +911,44 @@ class SceneGestureHandlerTest { assertIdle(SceneA) // Swipe up to B. - onDragStarted(overSlop = up(0.1f)) + val dragController1 = onDragStarted(overSlop = up(0.1f)) assertTransition(currentScene = SceneA, fromScene = SceneA, toScene = SceneB) - onDragStopped(velocity = -velocityThreshold) + dragController1.onDragStopped(velocity = -velocityThreshold) assertTransition(currentScene = SceneB, fromScene = SceneA, toScene = SceneB) // Intercept the transition and swipe down back to scene A. - assertThat(sceneGestureHandler.shouldImmediatelyIntercept(startedPosition = null)).isTrue() - onDragStartedImmediately() + assertThat(draggableHandler.shouldImmediatelyIntercept(startedPosition = null)).isTrue() + val dragController2 = onDragStartedImmediately() // Block the transition when the user release their finger. canChangeScene = { false } - onDragStopped(velocity = velocityThreshold) + dragController2.onDragStopped(velocity = velocityThreshold) advanceUntilIdle() assertIdle(SceneB) } + + @Test + fun scrollFromIdleWithNoTargetScene_shouldUseOverscrollSpecIfAvailable() = runGestureTest { + layoutState.transitions = transitions { + overscroll(SceneC, Orientation.Vertical) { fade(TestElements.Foo) } + } + // Start at scene C. + navigateToSceneC() + + val scene = layoutState.transitionState.currentScene + // We should have overscroll spec for scene C + assertThat(layoutState.transitions.overscrollSpec(scene, Orientation.Vertical)).isNotNull() + assertThat(layoutState.currentOverscrollSpec).isNull() + + val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways) + nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f)) + + // We scrolled down, under scene C there is nothing, so we can use the overscroll spec + assertThat(layoutState.currentOverscrollSpec).isNotNull() + assertThat(layoutState.currentOverscrollSpec?.scene).isEqualTo(SceneC) + val transition = layoutState.currentTransition + assertThat(transition).isNotNull() + assertThat(transition!!.progress).isEqualTo(-0.1f) + } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt index 33be1dc83dc8..059a10e23207 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt @@ -18,9 +18,13 @@ package com.android.compose.animation.scene import androidx.compose.animation.core.tween import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.rememberScrollableState +import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.size @@ -34,8 +38,14 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.layout.intermediateLayout +import androidx.compose.ui.platform.LocalViewConfiguration +import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.performTouchInput import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -528,4 +538,157 @@ class ElementTest { after { assertThat(fooCompositions).isEqualTo(1) } } } + + @Test + fun elementTransitionDuringOverscroll() { + // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is + // detected as a drag event. + var touchSlop = 0f + val overscrollTranslateY = 10.dp + val layoutWidth = 200.dp + val layoutHeight = 400.dp + + val state = + MutableSceneTransitionLayoutState( + initialScene = TestScenes.SceneA, + transitions = + transitions { + overscroll(TestScenes.SceneB, Orientation.Vertical) { + translate(TestElements.Foo, y = overscrollTranslateY) + } + } + ) + as MutableSceneTransitionLayoutStateImpl + + rule.setContent { + touchSlop = LocalViewConfiguration.current.touchSlop + SceneTransitionLayout( + state = state, + modifier = Modifier.size(layoutWidth, layoutHeight) + ) { + scene( + key = TestScenes.SceneA, + userActions = mapOf(Swipe.Down to TestScenes.SceneB) + ) { + Spacer(Modifier.fillMaxSize()) + } + scene(TestScenes.SceneB) { + Spacer(Modifier.element(TestElements.Foo).fillMaxSize()) + } + } + } + + assertThat(state.currentTransition).isNull() + assertThat(state.currentOverscrollSpec).isNull() + + // Swipe by half of verticalSwipeDistance. + rule.onRoot().performTouchInput { + val middleTop = Offset((layoutWidth / 2).toPx(), 0f) + down(middleTop) + // Scroll 50% + moveBy(Offset(0f, touchSlop + layoutHeight.toPx() * 0.5f), delayMillis = 1_000) + } + + val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true) + fooElement.assertTopPositionInRootIsEqualTo(0.dp) + val transition = state.currentTransition + assertThat(transition).isNotNull() + assertThat(transition!!.progress).isEqualTo(0.5f) + + rule.onRoot().performTouchInput { + // Scroll another 100% + moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) + } + + // Scroll 150% (Scene B overscroll by 50%) + assertThat(transition.progress).isEqualTo(1.5f) + assertThat(state.currentOverscrollSpec).isNotNull() + fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f) + + rule.onRoot().performTouchInput { + // Scroll another 100% + moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) + } + + // Scroll 250% (Scene B overscroll by 150%) + assertThat(transition.progress).isEqualTo(2.5f) + assertThat(state.currentOverscrollSpec).isNotNull() + fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f) + } + + @Test + fun elementTransitionDuringNestedScrollOverscroll() { + // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is + // detected as a drag event. + var touchSlop = 0f + val overscrollTranslateY = 10.dp + val layoutWidth = 200.dp + val layoutHeight = 400.dp + + val state = + MutableSceneTransitionLayoutState( + initialScene = TestScenes.SceneB, + transitions = + transitions { + overscroll(TestScenes.SceneB, Orientation.Vertical) { + translate(TestElements.Foo, y = overscrollTranslateY) + } + } + ) + as MutableSceneTransitionLayoutStateImpl + + rule.setContent { + touchSlop = LocalViewConfiguration.current.touchSlop + SceneTransitionLayout( + state = state, + modifier = Modifier.size(layoutWidth, layoutHeight) + ) { + scene(TestScenes.SceneA) { Spacer(Modifier.fillMaxSize()) } + scene(TestScenes.SceneB, userActions = mapOf(Swipe.Up to TestScenes.SceneA)) { + Box( + Modifier + // Unconsumed scroll gesture will be intercepted by STL + .verticalNestedScrollToScene() + // A scrollable that does not consume the scroll gesture + .scrollable( + rememberScrollableState(consumeScrollDelta = { 0f }), + Orientation.Vertical + ) + .fillMaxSize() + ) { + Spacer(Modifier.element(TestElements.Foo).fillMaxSize()) + } + } + } + } + + assertThat(state.currentTransition).isNull() + assertThat(state.currentOverscrollSpec).isNull() + val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true) + fooElement.assertTopPositionInRootIsEqualTo(0.dp) + + // Swipe by half of verticalSwipeDistance. + rule.onRoot().performTouchInput { + val middleTop = Offset((layoutWidth / 2).toPx(), 0f) + down(middleTop) + // Scroll 50% + moveBy(Offset(0f, touchSlop + layoutHeight.toPx() * 0.5f), delayMillis = 1_000) + } + + val transition = state.currentTransition + assertThat(state.currentOverscrollSpec).isNotNull() + assertThat(transition).isNotNull() + assertThat(transition!!.progress).isEqualTo(-0.5f) + fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f) + + rule.onRoot().performTouchInput { + // Scroll another 100% + moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000) + } + + // Scroll 150% (Scene B overscroll by 50%) + assertThat(transition.progress).isEqualTo(-1.5f) + assertThat(state.currentOverscrollSpec).isNotNull() + fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f) + } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt index cd99d05158cd..d8cf1c12989b 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MultiPointerDraggableTest.kt @@ -59,9 +59,18 @@ class MultiPointerDraggableTest { orientation = Orientation.Vertical, enabled = { enabled }, startDragImmediately = { false }, - onDragStarted = { _, _, _ -> started = true }, - onDragDelta = { _ -> dragged = true }, - onDragStopped = { stopped = true }, + onDragStarted = { _, _, _ -> + started = true + object : DragController { + override fun onDrag(delta: Float) { + dragged = true + } + + override fun onStop(velocity: Float, canChangeScene: Boolean) { + stopped = true + } + } + }, ) ) } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt index f81a7f2908e8..3cbcd73a0adb 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt @@ -16,6 +16,8 @@ package com.android.compose.animation.scene +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.test.junit4.createComposeRule import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.animation.scene.TestScenes.SceneA @@ -389,4 +391,118 @@ class SceneTransitionLayoutStateTest { assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue() assertThat(parentState.isTransitioning(SceneC, SceneD)).isFalse() } + + private fun startOverscrollableTransistionFromAtoB( + progress: () -> Float, + sceneTransitions: SceneTransitions, + ): MutableSceneTransitionLayoutStateImpl { + val state = + MutableSceneTransitionLayoutStateImpl( + SceneA, + sceneTransitions, + ) + state.startTransition( + object : + TransitionState.Transition(SceneA, SceneB), + TransitionState.HasOverscrollProperties { + override val currentScene: SceneKey = SceneA + override val progress: Float + get() = progress() + + override val isInitiatedByUserInput: Boolean = false + override val isUserInputOngoing: Boolean = false + override val isUpOrLeft: Boolean = false + override val orientation: Orientation = Orientation.Vertical + }, + transitionKey = null + ) + assertThat(state.isTransitioning()).isTrue() + return state + } + + @Test + fun overscrollDsl_definedForToScene() = runMonotonicClockTest { + val progress = mutableStateOf(0f) + val state = + startOverscrollableTransistionFromAtoB( + progress = { progress.value }, + sceneTransitions = + transitions { + overscroll(SceneB, Orientation.Vertical) { fade(TestElements.Foo) } + } + ) + assertThat(state.currentOverscrollSpec).isNull() + + // overscroll for SceneA is NOT defined + progress.value = -0.1f + assertThat(state.currentOverscrollSpec).isNull() + + // scroll from SceneA to SceneB + progress.value = 0.5f + assertThat(state.currentOverscrollSpec).isNull() + + progress.value = 1f + assertThat(state.currentOverscrollSpec).isNull() + + // overscroll for SceneB is defined + progress.value = 1.1f + assertThat(state.currentOverscrollSpec).isNotNull() + assertThat(state.currentOverscrollSpec?.scene).isEqualTo(SceneB) + } + + @Test + fun overscrollDsl_definedForFromScene() = runMonotonicClockTest { + val progress = mutableStateOf(0f) + val state = + startOverscrollableTransistionFromAtoB( + progress = { progress.value }, + sceneTransitions = + transitions { + overscroll(SceneA, Orientation.Vertical) { fade(TestElements.Foo) } + } + ) + assertThat(state.currentOverscrollSpec).isNull() + + // overscroll for SceneA is defined + progress.value = -0.1f + assertThat(state.currentOverscrollSpec).isNotNull() + assertThat(state.currentOverscrollSpec?.scene).isEqualTo(SceneA) + + // scroll from SceneA to SceneB + progress.value = 0.5f + assertThat(state.currentOverscrollSpec).isNull() + + progress.value = 1f + assertThat(state.currentOverscrollSpec).isNull() + + // overscroll for SceneB is NOT defined + progress.value = 1.1f + assertThat(state.currentOverscrollSpec).isNull() + } + + @Test + fun overscrollDsl_notDefinedScenes() = runMonotonicClockTest { + val progress = mutableStateOf(0f) + val state = + startOverscrollableTransistionFromAtoB( + progress = { progress.value }, + sceneTransitions = transitions {} + ) + assertThat(state.currentOverscrollSpec).isNull() + + // overscroll for SceneA is NOT defined + progress.value = -0.1f + assertThat(state.currentOverscrollSpec).isNull() + + // scroll from SceneA to SceneB + progress.value = 0.5f + assertThat(state.currentOverscrollSpec).isNull() + + progress.value = 1f + assertThat(state.currentOverscrollSpec).isNull() + + // overscroll for SceneB is NOT defined + progress.value = 1.1f + assertThat(state.currentOverscrollSpec).isNull() + } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt index 543ed0482430..99372a5d084b 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt @@ -16,9 +16,11 @@ package com.android.compose.animation.scene +import androidx.compose.foundation.gestures.Orientation import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -33,6 +35,7 @@ import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.performTouchInput import androidx.compose.ui.test.swipeWithVelocity import androidx.compose.ui.unit.Density +import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat @@ -61,8 +64,10 @@ class SwipeToSceneTest { @get:Rule val rule = createComposeRule() - private fun layoutState(initialScene: SceneKey = TestScenes.SceneA) = - MutableSceneTransitionLayoutState(initialScene, EmptyTestTransitions) + private fun layoutState( + initialScene: SceneKey = TestScenes.SceneA, + transitions: SceneTransitions = EmptyTestTransitions, + ) = MutableSceneTransitionLayoutState(initialScene, transitions) /** The content under test. */ @Composable @@ -370,8 +375,16 @@ class SwipeToSceneTest { // detected as a drag event. var touchSlop = 0f - val layoutState = layoutState() val verticalSwipeDistance = 50.dp + val layoutState = + layoutState( + transitions = + transitions { + from(TestScenes.SceneA, to = TestScenes.SceneB) { + distance = FixedDistance(verticalSwipeDistance) + } + } + ) assertThat(verticalSwipeDistance).isNotEqualTo(LayoutHeight) rule.setContent { @@ -383,14 +396,7 @@ class SwipeToSceneTest { ) { scene( TestScenes.SceneA, - userActions = - mapOf( - Swipe.Down to - UserActionResult( - toScene = TestScenes.SceneB, - distance = verticalSwipeDistance, - ) - ), + userActions = mapOf(Swipe.Down to TestScenes.SceneB), ) { Spacer(Modifier.fillMaxSize()) } @@ -548,4 +554,64 @@ class SwipeToSceneTest { assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue() assertThat(state.transformationSpec.transformations).hasSize(2) } + + @Test + fun dynamicSwipeDistance() { + val swipeDistance = + object : UserActionDistance { + override fun UserActionDistanceScope.absoluteDistance( + fromSceneSize: IntSize, + orientation: Orientation, + ): Float { + // Foo is going to have a vertical offset of 50dp. Let's make the swipe distance + // the difference between the bottom of the scene and the bottom of the element, + // so that we use the offset and size of the element as well as the size of the + // scene. + val fooSize = TestElements.Foo.targetSize(TestScenes.SceneB) ?: return 0f + val fooOffset = TestElements.Foo.targetOffset(TestScenes.SceneB) ?: return 0f + val sceneSize = TestScenes.SceneB.targetSize() ?: return 0f + return sceneSize.height - fooOffset.y - fooSize.height + } + } + + val state = + MutableSceneTransitionLayoutState( + TestScenes.SceneA, + transitions { + from(TestScenes.SceneA, to = TestScenes.SceneB) { distance = swipeDistance } + } + ) + + val layoutSize = 200.dp + val fooYOffset = 50.dp + val fooSize = 25.dp + + var touchSlop = 0f + rule.setContent { + touchSlop = LocalViewConfiguration.current.touchSlop + + SceneTransitionLayout(state, Modifier.size(layoutSize)) { + scene(TestScenes.SceneA, userActions = mapOf(Swipe.Up to TestScenes.SceneB)) { + Box(Modifier.fillMaxSize()) + } + scene(TestScenes.SceneB) { + Box(Modifier.fillMaxSize()) { + Box(Modifier.offset(y = fooYOffset).element(TestElements.Foo).size(fooSize)) + } + } + } + } + + // Swipe up by half the expected distance to get to 50% progress. + val expectedDistance = layoutSize - fooYOffset - fooSize + rule.onRoot().performTouchInput { + val middle = (layoutSize / 2).toPx() + down(Offset(middle, middle)) + moveBy(Offset(0f, -touchSlop - (expectedDistance / 2f).toPx()), delayMillis = 1_000) + } + + rule.waitForIdle() + assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue() + assertThat(state.currentTransition!!.progress).isWithin(0.01f).of(0.5f) + } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt index 1beafcc2cbb2..c9c3eccdedfc 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt @@ -20,9 +20,11 @@ import androidx.compose.animation.core.SpringSpec import androidx.compose.animation.core.TweenSpec import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween +import androidx.compose.foundation.gestures.Orientation import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.animation.scene.transformation.Transformation import com.android.compose.animation.scene.transformation.TransformationRange +import com.android.compose.animation.scene.transformation.Translate import com.google.common.truth.Correspondence import com.google.common.truth.Truth.assertThat import org.junit.Test @@ -223,6 +225,17 @@ class TransitionDslTest { .isSameInstanceAs(specFromAToC) } + @Test + fun overscrollSpec() { + val transitions = transitions { + overscroll(TestScenes.SceneA, Orientation.Vertical) { translate(TestElements.Bar) } + } + + val overscrollSpec = transitions.overscrollSpecs.single() + val transformation = overscrollSpec.transformationSpec.transformations.single() + assertThat(transformation).isInstanceOf(Translate::class.java) + } + companion object { private val TRANSFORMATION_RANGE = Correspondence.transforming<Transformation, TransformationRange?>( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/data/repository/AssistRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/data/repository/AssistRepositoryTest.kt new file mode 100644 index 000000000000..80077a21f985 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/data/repository/AssistRepositoryTest.kt @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.assist.data.repository + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class AssistRepositoryTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + + private val underTest = kosmos.assistRepository + + @Test + fun invocationType() = + testScope.runTest { + val invocationType by collectLastValue(underTest.latestInvocationType) + underTest.setLatestInvocationType(2) + runCurrent() + + assertThat(invocationType).isEqualTo(2) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/domain/interactor/AssistInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/domain/interactor/AssistInteractorTest.kt new file mode 100644 index 000000000000..c12f1aca350a --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/domain/interactor/AssistInteractorTest.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.assist.domain.interactor + +import android.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.Flags +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@RunWith(AndroidJUnit4::class) +@SmallTest +class AssistInteractorTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + + private val underTest = kosmos.assistInteractor + + @Test + @EnableFlags(Flags.FLAG_ENABLE_CONTEXTUAL_TIPS, Flags.FLAG_ENABLE_CONTEXTUAL_TIP_FOR_POWER_OFF) + fun onAssistantStarted() = + testScope.runTest { + val invocationType by collectLastValue(underTest.latestInvocationType) + underTest.onAssistantStarted(3) + runCurrent() + + assertThat(invocationType).isEqualTo(3) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt index 503463171ae7..92eb8f8c36c2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt @@ -30,6 +30,7 @@ import android.view.MotionEvent import android.view.Surface import android.view.Surface.Rotation import android.view.View +import android.view.ViewGroup import android.view.WindowManager import android.view.accessibility.AccessibilityManager import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -46,7 +47,12 @@ import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor import com.android.systemui.classifier.FalsingCollector import com.android.systemui.dump.DumpManager +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.domain.interactor.FromAodTransitionInteractor +import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor +import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.power.data.repository.FakePowerRepository import com.android.systemui.power.domain.interactor.PowerInteractor @@ -127,7 +133,8 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Mock private lateinit var defaultUdfpsTouchOverlayViewModel: DefaultUdfpsTouchOverlayViewModel @Mock private lateinit var udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate - @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor + private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository + private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor @Mock private lateinit var shadeInteractor: ShadeInteractor @Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams> @Mock private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor @@ -150,6 +157,19 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { mock(ScreenOffAnimationController::class.java), statusBarStateController, ) + keyguardTransitionRepository = FakeKeyguardTransitionRepository() + keyguardTransitionInteractor = + KeyguardTransitionInteractor( + scope = testScope.backgroundScope, + repository = keyguardTransitionRepository, + fromLockscreenTransitionInteractor = { + mock(FromLockscreenTransitionInteractor::class.java) + }, + fromPrimaryBouncerTransitionInteractor = { + mock(FromPrimaryBouncerTransitionInteractor::class.java) + }, + fromAodTransitionInteractor = { mock(FromAodTransitionInteractor::class.java) }, + ) whenever(inflater.inflate(R.layout.udfps_view, null, false)).thenReturn(udfpsView) whenever(inflater.inflate(R.layout.udfps_bp_view, null)) .thenReturn(mock(UdfpsBpView::class.java)) @@ -159,11 +179,25 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { .thenReturn(mock(UdfpsFpmEmptyView::class.java)) } + private suspend fun withReasonSuspend( + @RequestReason reason: Int, + isDebuggable: Boolean = false, + enableDeviceEntryUdfpsRefactor: Boolean = false, + block: suspend () -> Unit, + ) { + withReason( + reason, + isDebuggable, + enableDeviceEntryUdfpsRefactor, + ) + block() + } + private fun withReason( @RequestReason reason: Int, isDebuggable: Boolean = false, enableDeviceEntryUdfpsRefactor: Boolean = false, - block: () -> Unit, + block: () -> Unit = {}, ) { if (enableDeviceEntryUdfpsRefactor) { mSetFlagsRule.enableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR) @@ -312,6 +346,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { lastWakeReason = WakeSleepReason.POWER_BUTTON, lastSleepReason = WakeSleepReason.OTHER, ) + runCurrent() controllerOverlay.show(udfpsController, overlayParams) runCurrent() verify(windowManager).addView(any(), any()) @@ -321,15 +356,25 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { @Test fun showUdfpsOverlay_whileGoingToSleep() = testScope.runTest { - withReason(REASON_AUTH_KEYGUARD) { + withReasonSuspend(REASON_AUTH_KEYGUARD) { mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE) + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.OFF, + to = KeyguardState.GONE, + testScope = this, + ) powerRepository.updateWakefulness( rawState = WakefulnessState.STARTING_TO_SLEEP, lastWakeReason = WakeSleepReason.POWER_BUTTON, lastSleepReason = WakeSleepReason.OTHER, ) + runCurrent() + + // WHEN a request comes to show the view controllerOverlay.show(udfpsController, overlayParams) runCurrent() + + // THEN the view does not get added immediately verify(windowManager, never()).addView(any(), any()) // we hide to end the job that listens for the finishedGoingToSleep signal @@ -338,25 +383,82 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { } @Test - fun showUdfpsOverlay_afterFinishedGoingToSleep() = + fun showUdfpsOverlay_whileAsleep() = testScope.runTest { - withReason(REASON_AUTH_KEYGUARD) { + withReasonSuspend(REASON_AUTH_KEYGUARD) { mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE) + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.OFF, + to = KeyguardState.GONE, + testScope = this, + ) powerRepository.updateWakefulness( - rawState = WakefulnessState.STARTING_TO_SLEEP, + rawState = WakefulnessState.ASLEEP, lastWakeReason = WakeSleepReason.POWER_BUTTON, lastSleepReason = WakeSleepReason.OTHER, ) + runCurrent() + + // WHEN a request comes to show the view controllerOverlay.show(udfpsController, overlayParams) runCurrent() + + // THEN view isn't added yet verify(windowManager, never()).addView(any(), any()) + // we hide to end the job that listens for the finishedGoingToSleep signal + controllerOverlay.hide() + } + } + + @Test + fun neverRemoveViewThatHasNotBeenAdded() = + testScope.runTest { + withReasonSuspend(REASON_AUTH_KEYGUARD) { + mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE) + controllerOverlay.show(udfpsController, overlayParams) + val view = controllerOverlay.getTouchOverlay() + view?.let { + // parent is null, signalling that the view was never added + whenever(view.parent).thenReturn(null) + } + verify(windowManager, never()).removeView(eq(view)) + } + } + + @Test + fun showUdfpsOverlay_afterFinishedTransitioningToAOD() = + testScope.runTest { + withReasonSuspend(REASON_AUTH_KEYGUARD) { + mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE) + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.OFF, + to = KeyguardState.GONE, + testScope = this, + ) powerRepository.updateWakefulness( - rawState = WakefulnessState.ASLEEP, + rawState = WakefulnessState.STARTING_TO_SLEEP, lastWakeReason = WakeSleepReason.POWER_BUTTON, lastSleepReason = WakeSleepReason.OTHER, ) runCurrent() + + // WHEN a request comes to show the view + controllerOverlay.show(udfpsController, overlayParams) + runCurrent() + + // THEN the view does not get added immediately + verify(windowManager, never()).addView(any(), any()) + + // WHEN the device finishes transitioning to AOD + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.GONE, + to = KeyguardState.AOD, + testScope = this, + ) + runCurrent() + + // THEN the view gets added verify(windowManager) .addView(eq(controllerOverlay.getTouchOverlay()), layoutParamsCaptor.capture()) } @@ -387,6 +489,7 @@ class UdfpsControllerOverlayTest : SysuiTestCase() { private fun hideUdfpsOverlay() { val didShow = controllerOverlay.show(udfpsController, overlayParams) val view = controllerOverlay.getTouchOverlay() + view?.let { whenever(view.parent).thenReturn(mock(ViewGroup::class.java)) } val didHide = controllerOverlay.hide() verify(windowManager).removeView(eq(view)) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 561cdbbf66ce..9b0b5dea0ad7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -63,6 +63,7 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.Surface; import android.view.View; +import android.view.ViewGroup; import android.view.ViewRootImpl; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; @@ -234,6 +235,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private ArgumentCaptor<IUdfpsOverlayController> mOverlayCaptor; private IUdfpsOverlayController mOverlayController; @Captor + private ArgumentCaptor<View> mViewCaptor; + @Captor private ArgumentCaptor<UdfpsView.OnTouchListener> mTouchListenerCaptor; @Captor private ArgumentCaptor<View.OnHoverListener> mHoverListenerCaptor; @@ -550,8 +553,11 @@ public class UdfpsControllerTest extends SysuiTestCase { mOpticalProps.sensorId, BiometricRequestConstants.REASON_ENROLL_ENROLLING, mUdfpsOverlayControllerCallback); + mFgExecutor.runAllReady(); - verify(mWindowManager).addView(any(), any()); + verify(mWindowManager).addView(mViewCaptor.capture(), any()); + when(mViewCaptor.getValue().getParent()) + .thenReturn(mock(ViewGroup.class)); // Update overlay parameters. reset(mWindowManager); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt index d86b35d3b95a..92396e0bcdef 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt @@ -93,25 +93,6 @@ class CommunalSceneStartableTest : SysuiTestCase() { } @Test - fun deviceDreaming_forceBlankScene() = - with(kosmos) { - testScope.runTest { - val scene by collectLastValue(communalInteractor.desiredScene) - - communalInteractor.onSceneChanged(CommunalSceneKey.Communal) - assertThat(scene).isEqualTo(CommunalSceneKey.Communal) - - fakeKeyguardTransitionRepository.sendTransitionSteps( - from = KeyguardState.GLANCEABLE_HUB, - to = KeyguardState.DREAMING, - testScope = this - ) - - assertThat(scene).isEqualTo(CommunalSceneKey.Blank) - } - } - - @Test fun deviceDocked_forceCommunalScene() = with(kosmos) { testScope.runTest { @@ -125,13 +106,6 @@ class CommunalSceneStartableTest : SysuiTestCase() { testScope = this ) assertThat(scene).isEqualTo(CommunalSceneKey.Communal) - - fakeKeyguardTransitionRepository.sendTransitionSteps( - from = KeyguardState.GLANCEABLE_HUB, - to = KeyguardState.DREAMING, - testScope = this - ) - assertThat(scene).isEqualTo(CommunalSceneKey.Blank) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt index cd296524c17c..6e3573b64f9a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt @@ -27,6 +27,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.SysuiTestCase +import com.android.systemui.communal.data.repository.CommunalSettingsRepositoryImpl import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository import com.android.systemui.communal.data.repository.FakeCommunalPrefsRepository import com.android.systemui.communal.data.repository.FakeCommunalRepository @@ -62,6 +63,7 @@ import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.settings.fakeSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow @@ -831,6 +833,95 @@ class CommunalInteractorTest : SysuiTestCase() { } } + @Test + fun widgetContent_containsDisabledWidgets_whenCategoryNotAllowed() = + testScope.runTest { + // Communal available, and tutorial completed. + keyguardRepository.setKeyguardShowing(true) + keyguardRepository.setKeyguardOccluded(false) + tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + userRepository.setSelectedUserInfo(mainUser) + + val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) + userRepository.setUserInfos(userInfos) + userTracker.set( + userInfos = userInfos, + selectedUserIndex = 0, + ) + runCurrent() + + // Widgets available. + val widget1 = + createWidgetWithCategory(1, AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN) + val widget2 = + createWidgetWithCategory(2, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) + val widget3 = + createWidgetWithCategory(3, AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX) + val widgets = listOf(widget1, widget2, widget3) + widgetRepository.setCommunalWidgets(widgets) + + val widgetContent by collectLastValue(underTest.widgetContent) + kosmos.fakeSettings.putIntForUser( + CommunalSettingsRepositoryImpl.GLANCEABLE_HUB_CONTENT_SETTING, + AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD, + mainUser.id + ) + runCurrent() + + // Only the keyguard widget is enabled. + assertThat(widgetContent).hasSize(3) + assertThat(widgetContent!!.get(0)) + .isInstanceOf(CommunalContentModel.WidgetContent.DisabledWidget::class.java) + assertThat(widgetContent!!.get(1)) + .isInstanceOf(CommunalContentModel.WidgetContent.Widget::class.java) + assertThat(widgetContent!!.get(2)) + .isInstanceOf(CommunalContentModel.WidgetContent.DisabledWidget::class.java) + } + + @Test + fun widgetContent_allEnabled_whenCategoryAllowed() = + testScope.runTest { + // Communal available, and tutorial completed. + keyguardRepository.setKeyguardShowing(true) + keyguardRepository.setKeyguardOccluded(false) + tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED) + userRepository.setSelectedUserInfo(mainUser) + + val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK) + userRepository.setUserInfos(userInfos) + userTracker.set( + userInfos = userInfos, + selectedUserIndex = 0, + ) + runCurrent() + + // Widgets available. + val widget1 = + createWidgetWithCategory(1, AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN) + val widget2 = + createWidgetWithCategory(2, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) + val widget3 = + createWidgetWithCategory(3, AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) + val widgets = listOf(widget1, widget2, widget3) + widgetRepository.setCommunalWidgets(widgets) + + val widgetContent by collectLastValue(underTest.widgetContent) + kosmos.fakeSettings.putIntForUser( + CommunalSettingsRepositoryImpl.GLANCEABLE_HUB_CONTENT_SETTING, + AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD or + AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN, + mainUser.id + ) + runCurrent() + + // All widgets are enabled. + assertThat(widgetContent).hasSize(3) + widgetContent!!.forEach { model -> + assertThat(model) + .isInstanceOf(CommunalContentModel.WidgetContent.Widget::class.java) + } + } + private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget { val timer = mock(SmartspaceTarget::class.java) whenever(timer.smartspaceTargetId).thenReturn(id) @@ -848,6 +939,17 @@ class CommunalInteractorTest : SysuiTestCase() { whenever(this.providerInfo).thenReturn(providerInfo) } + private fun createWidgetWithCategory( + appWidgetId: Int, + category: Int + ): CommunalWidgetContentModel = + mock<CommunalWidgetContentModel> { + whenever(this.appWidgetId).thenReturn(appWidgetId) + val providerInfo = mock<AppWidgetProviderInfo>().apply { widgetCategory = category } + whenever(providerInfo.profile).thenReturn(UserHandle(MAIN_USER_INFO.id)) + whenever(this.providerInfo).thenReturn(providerInfo) + } + private companion object { val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN) val USER_INFO_WORK = UserInfo(10, "work", UserInfo.FLAG_PROFILE) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt index 5ee88cb92fa0..8e2e94716660 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt @@ -135,9 +135,9 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { // Only Widgets and CTA tile are shown. assertThat(communalContent?.size).isEqualTo(3) assertThat(communalContent?.get(0)) - .isInstanceOf(CommunalContentModel.Widget::class.java) + .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(1)) - .isInstanceOf(CommunalContentModel.Widget::class.java) + .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(2)) .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java) } @@ -181,9 +181,9 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { // Widgets and CTA tile are shown. assertThat(communalContent?.size).isEqualTo(3) assertThat(communalContent?.get(0)) - .isInstanceOf(CommunalContentModel.Widget::class.java) + .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(1)) - .isInstanceOf(CommunalContentModel.Widget::class.java) + .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(2)) .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java) @@ -192,7 +192,8 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { // Only one widget and CTA tile remain. assertThat(communalContent?.size).isEqualTo(2) val item = communalContent?.get(0) - val appWidgetId = if (item is CommunalContentModel.Widget) item.appWidgetId else null + val appWidgetId = + if (item is CommunalContentModel.WidgetContent) item.appWidgetId else null assertThat(appWidgetId).isEqualTo(widgets.get(1).appWidgetId) assertThat(communalContent?.get(1)) .isInstanceOf(CommunalContentModel.CtaTileInEditMode::class.java) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt index 1e523dd2a9cc..563aad1920f7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt @@ -184,9 +184,9 @@ class CommunalViewModelTest : SysuiTestCase() { .isInstanceOf(CommunalContentModel.Smartspace::class.java) assertThat(communalContent?.get(1)).isInstanceOf(CommunalContentModel.Umo::class.java) assertThat(communalContent?.get(2)) - .isInstanceOf(CommunalContentModel.Widget::class.java) + .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(3)) - .isInstanceOf(CommunalContentModel.Widget::class.java) + .isInstanceOf(CommunalContentModel.WidgetContent::class.java) assertThat(communalContent?.get(4)) .isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java) } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt index 12611cbd8c63..88f5e1b85840 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt @@ -17,8 +17,10 @@ package com.android.systemui.communal.widgets import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProviderInfo import android.content.ComponentName import android.content.pm.UserInfo +import android.os.Bundle import android.os.UserHandle import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest @@ -33,8 +35,8 @@ import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.user.domain.interactor.selectedUserInteractor import com.android.systemui.util.mockito.any -import com.android.systemui.util.mockito.nullable import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat import java.util.Optional import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -43,6 +45,7 @@ import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.eq import org.mockito.Mock import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @@ -91,7 +94,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { any<Int>(), any<UserHandle>(), any<ComponentName>(), - nullable() + any<Bundle>(), ) ) .thenReturn(true) @@ -100,8 +103,14 @@ class CommunalWidgetHostTest : SysuiTestCase() { val result = underTest.allocateIdAndBindWidget(provider) verify(appWidgetHost).allocateAppWidgetId() - verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null) + val bundle = + withArgCaptor<Bundle> { + verify(appWidgetManager) + .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), capture()) + } assertThat(result).isEqualTo(widgetId) + assertThat(bundle.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) + .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) } @Test @@ -117,7 +126,7 @@ class CommunalWidgetHostTest : SysuiTestCase() { any<Int>(), any<UserHandle>(), any<ComponentName>(), - nullable() + any<Bundle>() ) ) .thenReturn(true) @@ -126,8 +135,14 @@ class CommunalWidgetHostTest : SysuiTestCase() { val result = underTest.allocateIdAndBindWidget(provider, user) verify(appWidgetHost).allocateAppWidgetId() - verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null) + val bundle = + withArgCaptor<Bundle> { + verify(appWidgetManager) + .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), capture()) + } assertThat(result).isEqualTo(widgetId) + assertThat(bundle.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) + .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) } @Test @@ -144,14 +159,15 @@ class CommunalWidgetHostTest : SysuiTestCase() { any<Int>(), any<UserHandle>(), any<ComponentName>(), - nullable() + any<Bundle>() ) ) .thenReturn(false) val result = underTest.allocateIdAndBindWidget(provider, user) verify(appWidgetHost).allocateAppWidgetId() - verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null) + verify(appWidgetManager) + .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), any()) verify(appWidgetHost).deleteAppWidgetId(widgetId) assertThat(result).isNull() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt index a6715dfcec24..c670506d9f04 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt @@ -11,7 +11,6 @@ import com.android.systemui.complication.ComplicationHostViewController import com.android.systemui.dreams.ui.viewmodel.DreamOverlayViewModel import com.android.systemui.log.core.FakeLogBuffer import com.android.systemui.statusbar.BlurUtils -import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever @@ -46,7 +45,6 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() { @Mock private lateinit var hostViewController: ComplicationHostViewController @Mock private lateinit var statusBarViewController: DreamOverlayStatusBarViewController @Mock private lateinit var stateController: DreamOverlayStateController - @Mock private lateinit var configController: ConfigurationController @Mock private lateinit var transitionViewModel: DreamOverlayViewModel private val logBuffer = FakeLogBuffer.Factory.create() private lateinit var controller: DreamOverlayAnimationsController @@ -62,7 +60,6 @@ class DreamOverlayAnimationsControllerTest : SysuiTestCase() { stateController, DREAM_BLUR_RADIUS, transitionViewModel, - configController, DREAM_IN_BLUR_ANIMATION_DURATION, DREAM_IN_COMPLICATIONS_ANIMATION_DURATION, DREAM_IN_TRANSLATION_Y_DISTANCE, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt index 558e7e6564ae..3a28471b5f9a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt @@ -33,6 +33,7 @@ import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticati import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runCurrent @@ -215,6 +216,39 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() { } @Test + fun onFingerprintFailed_failedAuthenticationStatusWithOtherStatuses() = + testScope.runTest { + val failStatus by + collectLastValue( + underTest.authenticationStatus.filterIsInstance< + FailFingerprintAuthenticationStatus + >() + ) + runCurrent() + + verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture()) + updateMonitorCallback.value.onBiometricAcquired( + BiometricSourceType.FINGERPRINT, + /* acquireInfo */ 0, + ) + updateMonitorCallback.value.onBiometricAuthFailed( + BiometricSourceType.FINGERPRINT, + ) + updateMonitorCallback.value.onBiometricHelp( + /* msgId */ 7, + /* errString */ "Not recognized.", + BiometricSourceType.FINGERPRINT, + ) + updateMonitorCallback.value.onBiometricError( + /* msgId */ 7, + /* errString */ "Too many attempts.", + BiometricSourceType.FINGERPRINT, + ) + + assertThat(failStatus).isNotNull() + } + + @Test fun onFingerprintError_errorAuthenticationStatus() = testScope.runTest { val authenticationStatus by collectLastValue(underTest.authenticationStatus) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt index 3484025f8d80..cd4db2fbf55f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt @@ -79,34 +79,66 @@ class KeyguardTransitionInteractorTest : SysuiTestCase() { } @Test - fun dozeAmountTransitionTest() = runTest { - val dozeAmountSteps by collectValues(underTest.dozeAmountTransition) + fun dozeAmountTransitionTest_AodToFromLockscreen() = + testScope.runTest { + val dozeAmountSteps by collectValues(underTest.dozeAmountTransition) - val steps = mutableListOf<TransitionStep>() + val steps = mutableListOf<TransitionStep>() - steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)) - steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING)) - steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED)) - steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)) - steps.add(TransitionStep(LOCKSCREEN, AOD, 0.8f, RUNNING)) - steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING)) - steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED)) + steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED)) + steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING)) + steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED)) + steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED)) + steps.add(TransitionStep(LOCKSCREEN, AOD, 0.8f, RUNNING)) + steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING)) + steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED)) - steps.forEach { - repository.sendTransitionStep(it) - runCurrent() + steps.forEach { + repository.sendTransitionStep(it) + runCurrent() + } + + assertThat(dozeAmountSteps.subList(0, 3)) + .isEqualTo( + listOf( + steps[0].copy(value = 1f - steps[0].value), + steps[1].copy(value = 1f - steps[1].value), + steps[2].copy(value = 1f - steps[2].value), + ) + ) + assertThat(dozeAmountSteps.subList(3, 7)).isEqualTo(steps.subList(3, 7)) } - assertThat(dozeAmountSteps.subList(0, 3)) - .isEqualTo( - listOf( - steps[0].copy(value = 1f - steps[0].value), - steps[1].copy(value = 1f - steps[1].value), - steps[2].copy(value = 1f - steps[2].value), + @Test + fun dozeAmountTransitionTest_AodToFromGone() = + testScope.runTest { + val dozeAmountSteps by collectValues(underTest.dozeAmountTransition) + + val steps = mutableListOf<TransitionStep>() + + steps.add(TransitionStep(AOD, GONE, 0f, STARTED)) + steps.add(TransitionStep(AOD, GONE, 0.3f, RUNNING)) + steps.add(TransitionStep(AOD, GONE, 1f, FINISHED)) + steps.add(TransitionStep(GONE, AOD, 0f, STARTED)) + steps.add(TransitionStep(GONE, AOD, 0.1f, RUNNING)) + steps.add(TransitionStep(GONE, AOD, 0.3f, RUNNING)) + steps.add(TransitionStep(GONE, AOD, 1f, FINISHED)) + + steps.forEach { + repository.sendTransitionStep(it) + runCurrent() + } + + assertThat(dozeAmountSteps.subList(0, 3)) + .isEqualTo( + listOf( + steps[0].copy(value = 1f - steps[0].value), + steps[1].copy(value = 1f - steps[1].value), + steps[2].copy(value = 1f - steps[2].value), + ) ) - ) - assertThat(dozeAmountSteps.subList(3, 7)).isEqualTo(steps.subList(3, 7)) - } + assertThat(dozeAmountSteps.subList(3, 7)).isEqualTo(steps.subList(3, 7)) + } @Test fun finishedKeyguardStateTests() = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt index 199ffa6b87bd..3f6e2291fd1f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt @@ -19,15 +19,15 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase -import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.biometrics.shared.model.FingerprintSensorType import com.android.systemui.biometrics.shared.model.SensorStrength import com.android.systemui.coroutines.collectValues -import com.android.systemui.keyguard.data.repository.biometricSettingsRepository -import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.data.repository.biometricSettingsRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.KeyguardState.AOD import com.android.systemui.keyguard.shared.model.TransitionState @@ -63,7 +63,7 @@ class AlternateBouncerToAodTransitionViewModelTest : SysuiTestCase() { } @Test - fun deviceEntryParentViewAppear() = + fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() = testScope.runTest { fingerprintPropertyRepository.setProperties( sensorId = 0, @@ -90,6 +90,33 @@ class AlternateBouncerToAodTransitionViewModelTest : SysuiTestCase() { } @Test + fun deviceEntryParentViewDisappear_udfpsNotEnrolledAndEnabled() = + testScope.runTest { + fingerprintPropertyRepository.setProperties( + sensorId = 0, + strength = SensorStrength.STRONG, + sensorType = FingerprintSensorType.UDFPS_OPTICAL, + sensorLocations = emptyMap(), + ) + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(0f) } + } + + @Test fun deviceEntryBackgroundViewDisappear() = testScope.runTest { val values by collectValues(underTest.deviceEntryBackgroundViewAlpha) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelTest.kt new file mode 100644 index 000000000000..f8a6fc795b42 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelTest.kt @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.coroutines.collectValues +import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.data.repository.biometricSettingsRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class AlternateBouncerToDozingTransitionViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository + private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository + private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository + private lateinit var underTest: AlternateBouncerToDozingTransitionViewModel + + @Before + fun setUp() { + keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository + biometricSettingsRepository = kosmos.biometricSettingsRepository + underTest = kosmos.alternateBouncerToDozingTransitionViewModel + } + + @Test + fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(1f) } + } + + @Test + fun deviceEntryParentViewDisappear_udfpsNotEnrolledAndEnabled() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(0f) } + } + + @Test + fun deviceEntryBackgroundViewDisappear() = + testScope.runTest { + val values by collectValues(underTest.deviceEntryBackgroundViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(0f) } + } + + private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep { + return TransitionStep( + from = KeyguardState.ALTERNATE_BOUNCER, + to = KeyguardState.DOZING, + value = value, + transitionState = state, + ownerName = "AlternateBouncerToDozingTransitionViewModelTest" + ) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt index 4c972e9195e9..4c972e9195e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt index db8fbf604430..db8fbf604430 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToOccludedTransitionViewModelTest.kt diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt index ad2ae8b41af9..ad2ae8b41af9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/BouncerToGoneFlowsTest.kt diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt new file mode 100644 index 000000000000..7e937db842ff --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectValues +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class DozingToGoneTransitionViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository + private lateinit var underTest: DozingToGoneTransitionViewModel + + @Before + fun setUp() { + keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + underTest = kosmos.dozingToGoneTransitionViewModel + } + + @Test + fun deviceEntryParentViewDisappear() = + testScope.runTest { + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(0f) } + } + + private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep { + return TransitionStep( + from = KeyguardState.DOZING, + to = KeyguardState.GONE, + value = value, + transitionState = state, + ownerName = "DozingToGoneTransitionViewModelTest" + ) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt index 471029b17873..4a10d80430e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt @@ -54,6 +54,19 @@ class DozingToLockscreenTransitionViewModelTest : SysuiTestCase() { deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(1f) } } + @Test + fun deviceEntryBackgroundViewShows() = + testScope.runTest { + val backgroundViewAlpha by collectValues(underTest.deviceEntryBackgroundViewAlpha) + repository.sendTransitionStep(step(0f, TransitionState.STARTED)) + repository.sendTransitionStep(step(0.1f)) + repository.sendTransitionStep(step(0.3f)) + repository.sendTransitionStep(step(0.5f)) + repository.sendTransitionStep(step(0.6f)) + repository.sendTransitionStep(step(1f)) + backgroundViewAlpha.forEach { assertThat(it).isEqualTo(1f) } + } + private fun step( value: Float, state: TransitionState = TransitionState.RUNNING diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt new file mode 100644 index 000000000000..bf71bec9e1f6 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectValues +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class DozingToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository + private lateinit var underTest: DozingToPrimaryBouncerTransitionViewModel + + @Before + fun setUp() { + keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + underTest = kosmos.dozingToPrimaryBouncerTransitionViewModel + } + + @Test + fun deviceEntryParentViewDisappear() = + testScope.runTest { + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(0f) } + } + + private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep { + return TransitionStep( + from = KeyguardState.DOZING, + to = KeyguardState.PRIMARY_BOUNCER, + value = value, + transitionState = state, + ownerName = "DozingToPrimaryBouncerTransitionViewModelTest" + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt index 4defe8a08d3d..aba21c946e46 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt @@ -19,12 +19,14 @@ package com.android.systemui.keyguard.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository import com.android.systemui.coroutines.collectValues import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope +import com.android.systemui.res.R import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat @@ -38,6 +40,7 @@ class DreamingToGlanceableHubTransitionViewModelTest : SysuiTestCase() { val kosmos = testKosmos() val testScope = kosmos.testScope + val configurationRepository by lazy { kosmos.fakeConfigurationRepository } val underTest by lazy { kosmos.dreamingToGlanceableHubTransitionViewModel } @Test @@ -66,7 +69,12 @@ class DreamingToGlanceableHubTransitionViewModelTest : SysuiTestCase() { @Test fun dreamOverlayTranslationX() = testScope.runTest { - val values by collectValues(underTest.dreamOverlayTranslationX(100)) + configurationRepository.setDimensionPixelSize( + R.dimen.dreaming_to_hub_transition_dream_overlay_translation_x, + -100 + ) + + val values by collectValues(underTest.dreamOverlayTranslationX) assertThat(values).isEmpty() kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt new file mode 100644 index 000000000000..11890c74a418 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository +import com.android.systemui.coroutines.collectValues +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.res.R +import com.android.systemui.testKosmos +import com.google.common.collect.Range +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class GlanceableHubToDreamingTransitionViewModelTest : SysuiTestCase() { + val kosmos = testKosmos() + val testScope = kosmos.testScope + + val configurationRepository by lazy { kosmos.fakeConfigurationRepository } + val underTest by lazy { kosmos.glanceableHubToDreamingTransitionViewModel } + + @Test + fun dreamOverlayAlpha() = + testScope.runTest { + val values by collectValues(underTest.dreamOverlayAlpha) + assertThat(values).isEmpty() + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + // Should start running here... + step(0.1f), + step(0.5f), + // Up to here... + step(1f), + ), + testScope, + ) + + assertThat(values).hasSize(2) + values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) } + } + + @Test + fun dreamOverlayTranslationX() = + testScope.runTest { + configurationRepository.setDimensionPixelSize( + R.dimen.hub_to_dreaming_transition_dream_overlay_translation_x, + 100 + ) + + val values by collectValues(underTest.dreamOverlayTranslationX) + assertThat(values).isEmpty() + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0.3f), + step(0.6f), + ), + testScope, + ) + + assertThat(values).hasSize(3) + values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) } + } + + private fun step( + value: Float, + state: TransitionState = TransitionState.RUNNING + ): TransitionStep { + return TransitionStep( + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.DREAMING, + value = value, + transitionState = state, + ownerName = GlanceableHubToDreamingTransitionViewModelTest::class.java.simpleName + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelTest.kt new file mode 100644 index 000000000000..59a6ce75e912 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelTest.kt @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository +import com.android.systemui.coroutines.collectValues +import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class GoneToDozingTransitionViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository + private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository + private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository + private lateinit var underTest: GoneToDozingTransitionViewModel + + @Before + fun setUp() { + fingerprintPropertyRepository = kosmos.fakeFingerprintPropertyRepository + biometricSettingsRepository = kosmos.fakeBiometricSettingsRepository + keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + underTest = kosmos.goneToDozingTransitionViewModel + } + + @Test + fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) + + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(1f) } + } + + @Test + fun deviceEntryParentViewDisappear_noUdfpsEnrolled_noUpdates() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) + + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isNull() } + } + + private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep { + return TransitionStep( + from = KeyguardState.GONE, + to = KeyguardState.DOZING, + value = value, + transitionState = state, + ownerName = "GoneToDozingTransitionViewModelTest" + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt index 0b80ff8d6ca4..d4dd2ac78e2a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenContentViewModelTest.kt @@ -36,7 +36,6 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) -@android.platform.test.annotations.EnabledOnRavenwood class LockscreenContentViewModelTest : SysuiTestCase() { private val kosmos: Kosmos = testKosmos() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt index e139466c8096..bef951554b50 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModelTest.kt @@ -36,10 +36,10 @@ import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth.assertThat -import kotlin.test.Test import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest +import org.junit.Test import org.junit.runner.RunWith @ExperimentalCoroutinesApi diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt new file mode 100644 index 000000000000..86b3f33b7555 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.coroutines.collectValues +import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.data.repository.biometricSettingsRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class LockscreenToDozingTransitionViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository + private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository + private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository + private lateinit var underTest: LockscreenToDozingTransitionViewModel + + @Before + fun setUp() { + keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository + biometricSettingsRepository = kosmos.biometricSettingsRepository + underTest = kosmos.lockscreenToDozingTransitionViewModel + } + + @Test + fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(1f) } + } + + @Test + fun deviceEntryParentViewDisappear_udfpsNotEnrolled() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(0f) } + } + + + @Test + fun lockscreenAlphaFadesOutAndFinishesVisible() = + testScope.runTest { + val alpha by collectValues(underTest.lockscreenAlpha) + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.DOZING, + testScope, + ) + + assertThat(alpha[0]).isEqualTo(1f) + // Halfway through, it will have faded out + assertThat(alpha[1]).isEqualTo(0f) + // FINISHED alpha should be visible, to support pulsing + assertThat(alpha[2]).isEqualTo(1f) + } + + @Test + fun deviceEntryBackgroundViewDisappear() = + testScope.runTest { + val values by collectValues(underTest.deviceEntryBackgroundViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(0f) } + } + + private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep { + return TransitionStep( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.DOZING, + value = value, + transitionState = state, + ownerName = "LockscreenToDozingTransitionViewModelTest" + ) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt index e7aaddd94695..e7aaddd94695 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt index 7a564aca00bb..43ab93a18118 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToPrimaryBouncerTransitionViewModelTest.kt @@ -33,10 +33,10 @@ import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.testKosmos import com.google.common.collect.Range import com.google.common.truth.Truth -import kotlin.test.Test import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest +import org.junit.Test import org.junit.runner.RunWith @ExperimentalCoroutinesApi diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt index 1912987cc447..1912987cc447 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToAodTransitionViewModelTest.kt diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt index c55c27c3b516..c55c27c3b516 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToAodTransitionViewModelTest.kt diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt new file mode 100644 index 000000000000..28473b204ce3 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.coroutines.collectValues +import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository +import com.android.systemui.keyguard.data.repository.biometricSettingsRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class PrimaryBouncerToDozingTransitionViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository + private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository + private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository + private lateinit var underTest: PrimaryBouncerToDozingTransitionViewModel + + @Before + fun setUp() { + keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository + fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository + biometricSettingsRepository = kosmos.biometricSettingsRepository + underTest = kosmos.primaryBouncerToDozingTransitionViewModel + } + + @Test + fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(1f) } + } + + @Test + fun deviceEntryParentView_udfpsNotEnrolledAndEnabled_noUpdates() = + testScope.runTest { + fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) + val values by collectValues(underTest.deviceEntryParentViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isNull() } + } + + @Test + fun deviceEntryBackgroundViewDisappear() = + testScope.runTest { + val values by collectValues(underTest.deviceEntryBackgroundViewAlpha) + + keyguardTransitionRepository.sendTransitionSteps( + listOf( + step(0f, TransitionState.STARTED), + step(0f), + step(0.1f), + step(0.2f), + step(0.3f), + step(1f), + ), + testScope, + ) + + values.forEach { assertThat(it).isEqualTo(0f) } + } + + private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep { + return TransitionStep( + from = KeyguardState.PRIMARY_BOUNCER, + to = KeyguardState.DOZING, + value = value, + transitionState = state, + ownerName = "PrimaryBouncerToDozingTransitionViewModelTest" + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt index 47e1ee9c1b71..db1d5d91eb65 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModelTest.kt @@ -149,6 +149,42 @@ class PrimaryBouncerToGoneTransitionViewModelTest : SysuiTestCase() { values.forEach { assertThat(it).isEqualTo(1f) } } + @Test + fun notificationAlpha() = + testScope.runTest { + val values by collectValues(underTest.notificationAlpha) + runCurrent() + + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.PRIMARY_BOUNCER, + to = KeyguardState.GONE, + testScope, + ) + + assertThat(values[0]).isEqualTo(1f) + // Should fade to zero between here + assertThat(values[1]).isEqualTo(0f) + } + + @Test + fun notificationAlpha_leaveShadeOpen() = + testScope.runTest { + val values by collectValues(underTest.notificationAlpha) + runCurrent() + + sysuiStatusBarStateController.setLeaveOpenOnKeyguardHide(true) + + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.PRIMARY_BOUNCER, + to = KeyguardState.GONE, + testScope, + ) + + assertThat(values.size).isEqualTo(2) + // Shade stays open, and alpha should remain visible + values.forEach { assertThat(it).isEqualTo(1f) } + } + private fun step( value: Float, state: TransitionState = TransitionState.RUNNING diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt index 0796af065790..0796af065790 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToLockscreenTransitionViewModelTest.kt diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/domain/interactor/SpatializerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/domain/interactor/SpatializerInteractorTest.kt new file mode 100644 index 000000000000..a932dd6d106d --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/domain/interactor/SpatializerInteractorTest.kt @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.media.domain.interactor + +import android.media.AudioDeviceAttributes +import android.media.AudioDeviceInfo +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.settingslib.media.domain.interactor.SpatializerInteractor +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.testScope +import com.android.systemui.media.spatializerRepository +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class SpatializerInteractorTest : SysuiTestCase() { + + private val kosmos = testKosmos() + private val underTest = SpatializerInteractor(kosmos.spatializerRepository) + + @Test + fun setSpatialAudioEnabledFalse_isEnabled_false() { + with(kosmos) { + testScope.runTest { + underTest.setSpatialAudioEnabled(deviceAttributes, false) + + assertThat(underTest.isSpatialAudioEnabled(deviceAttributes)).isFalse() + } + } + } + + @Test + fun setSpatialAudioEnabledTrue_isEnabled_true() { + with(kosmos) { + testScope.runTest { + underTest.setSpatialAudioEnabled(deviceAttributes, true) + + assertThat(underTest.isSpatialAudioEnabled(deviceAttributes)).isTrue() + } + } + } + + @Test + fun setHeadTrackingEnabledFalse_isEnabled_false() { + with(kosmos) { + testScope.runTest { + underTest.setHeadTrackingEnabled(deviceAttributes, false) + + assertThat(underTest.isHeadTrackingEnabled(deviceAttributes)).isFalse() + } + } + } + + @Test + fun setHeadTrackingEnabledTrue_isEnabled_true() { + with(kosmos) { + testScope.runTest { + underTest.setHeadTrackingEnabled(deviceAttributes, true) + + assertThat(underTest.isHeadTrackingEnabled(deviceAttributes)).isTrue() + } + } + } + + private companion object { + val deviceAttributes = + AudioDeviceAttributes( + AudioDeviceAttributes.ROLE_OUTPUT, + AudioDeviceInfo.TYPE_BLE_HEADSET, + "test_address", + ) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt index 4e72843922e1..fff0a316cbf4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt @@ -40,6 +40,7 @@ import com.android.systemui.bouncer.ui.viewmodel.PinBouncerViewModel import com.android.systemui.bouncer.ui.viewmodel.bouncerViewModel import com.android.systemui.classifier.domain.interactor.falsingInteractor import com.android.systemui.classifier.falsingCollector +import com.android.systemui.classifier.falsingManager import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository @@ -265,6 +266,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { displayId = displayTracker.defaultDisplayId, sceneLogger = mock(), falsingCollector = kosmos.falsingCollector, + falsingManager = kosmos.falsingManager, powerInteractor = powerInteractor, bouncerInteractor = bouncerInteractor, simBouncerInteractor = dagger.Lazy { kosmos.simBouncerInteractor }, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractorTest.kt new file mode 100644 index 000000000000..9b0adb172e8d --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractorTest.kt @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.scene.domain.interactor + +import android.platform.test.annotations.DisableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_SCENE_CONTAINER +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository +import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor +import com.android.systemui.flags.EnableSceneContainer +import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.shared.model.ObservableTransitionState +import com.android.systemui.scene.shared.model.SceneKey +import com.android.systemui.scene.shared.model.fakeSceneDataSource +import com.android.systemui.shade.data.repository.fakeShadeRepository +import com.android.systemui.statusbar.notification.stack.ui.viewmodel.panelExpansionInteractor +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class PanelExpansionInteractorTest : SysuiTestCase() { + + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository + private val deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor + private val sceneInteractor = kosmos.sceneInteractor + private val transitionState = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Idle(SceneKey.Lockscreen) + ) + private val fakeSceneDataSource = kosmos.fakeSceneDataSource + private val fakeShadeRepository = kosmos.fakeShadeRepository + + private lateinit var underTest: PanelExpansionInteractor + + @Before + fun setUp() { + sceneInteractor.setTransitionState(transitionState) + } + + @Test + @EnableSceneContainer + fun legacyPanelExpansion_whenIdle_whenLocked() = + testScope.runTest { + underTest = kosmos.panelExpansionInteractor + setUnlocked(false) + val panelExpansion by collectLastValue(underTest.legacyPanelExpansion) + + changeScene(SceneKey.Lockscreen) { assertThat(panelExpansion).isEqualTo(1f) } + assertThat(panelExpansion).isEqualTo(1f) + + changeScene(SceneKey.Bouncer) { assertThat(panelExpansion).isEqualTo(1f) } + assertThat(panelExpansion).isEqualTo(1f) + + changeScene(SceneKey.Shade) { assertThat(panelExpansion).isEqualTo(1f) } + assertThat(panelExpansion).isEqualTo(1f) + + changeScene(SceneKey.QuickSettings) { assertThat(panelExpansion).isEqualTo(1f) } + assertThat(panelExpansion).isEqualTo(1f) + + changeScene(SceneKey.Communal) { assertThat(panelExpansion).isEqualTo(1f) } + assertThat(panelExpansion).isEqualTo(1f) + } + + @Test + @EnableSceneContainer + fun legacyPanelExpansion_whenIdle_whenUnlocked() = + testScope.runTest { + underTest = kosmos.panelExpansionInteractor + setUnlocked(true) + val panelExpansion by collectLastValue(underTest.legacyPanelExpansion) + + changeScene(SceneKey.Gone) { assertThat(panelExpansion).isEqualTo(0f) } + assertThat(panelExpansion).isEqualTo(0f) + + changeScene(SceneKey.Shade) { progress -> + assertThat(panelExpansion).isEqualTo(progress) + } + assertThat(panelExpansion).isEqualTo(1f) + + changeScene(SceneKey.QuickSettings) { + // Shade's already expanded, so moving to QS should also be 1f. + assertThat(panelExpansion).isEqualTo(1f) + } + assertThat(panelExpansion).isEqualTo(1f) + + changeScene(SceneKey.Communal) { assertThat(panelExpansion).isEqualTo(1f) } + assertThat(panelExpansion).isEqualTo(1f) + } + + @Test + @DisableFlags(FLAG_SCENE_CONTAINER) + fun legacyPanelExpansion_whenInLegacyMode() = + testScope.runTest { + underTest = kosmos.panelExpansionInteractor + val leet = 0.1337f + fakeShadeRepository.setLegacyShadeExpansion(leet) + setUnlocked(false) + val panelExpansion by collectLastValue(underTest.legacyPanelExpansion) + + changeScene(SceneKey.Lockscreen) + assertThat(panelExpansion).isEqualTo(leet) + + changeScene(SceneKey.Bouncer) + assertThat(panelExpansion).isEqualTo(leet) + + changeScene(SceneKey.Shade) + assertThat(panelExpansion).isEqualTo(leet) + + changeScene(SceneKey.QuickSettings) + assertThat(panelExpansion).isEqualTo(leet) + + changeScene(SceneKey.Communal) + assertThat(panelExpansion).isEqualTo(leet) + } + + private fun TestScope.setUnlocked(isUnlocked: Boolean) { + val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked) + deviceEntryRepository.setUnlocked(isUnlocked) + runCurrent() + + assertThat(isDeviceUnlocked).isEqualTo(isUnlocked) + } + + private fun TestScope.changeScene( + toScene: SceneKey, + assertDuringProgress: ((progress: Float) -> Unit) = {}, + ) { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val progressFlow = MutableStateFlow(0f) + transitionState.value = + ObservableTransitionState.Transition( + fromScene = checkNotNull(currentScene), + toScene = toScene, + progress = progressFlow, + isInitiatedByUserInput = true, + isUserInputOngoing = flowOf(true), + ) + runCurrent() + assertDuringProgress(progressFlow.value) + + progressFlow.value = 0.2f + runCurrent() + assertDuringProgress(progressFlow.value) + + progressFlow.value = 0.6f + runCurrent() + assertDuringProgress(progressFlow.value) + + progressFlow.value = 1f + runCurrent() + assertDuringProgress(progressFlow.value) + + transitionState.value = ObservableTransitionState.Idle(toScene) + fakeSceneDataSource.changeScene(toScene) + runCurrent() + assertDuringProgress(progressFlow.value) + + assertThat(currentScene).isEqualTo(toScene) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt index f49b4777cf14..4e1623661a58 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt @@ -32,6 +32,7 @@ import com.android.systemui.authentication.shared.model.AuthenticationMethodMode import com.android.systemui.bouncer.domain.interactor.bouncerInteractor import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor import com.android.systemui.classifier.FalsingCollector +import com.android.systemui.classifier.falsingManager import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor @@ -115,6 +116,7 @@ class SceneContainerStartableTest : SysuiTestCase() { displayId = Display.DEFAULT_DISPLAY, sceneLogger = mock(), falsingCollector = falsingCollector, + falsingManager = kosmos.falsingManager, powerInteractor = powerInteractor, bouncerInteractor = bouncerInteractor, simBouncerInteractor = { kosmos.simBouncerInteractor }, @@ -970,6 +972,20 @@ class SceneContainerStartableTest : SysuiTestCase() { ) } + @Test + fun respondToFalsingDetections() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val transitionStateFlow = prepareState() + underTest.start() + emulateSceneTransition(transitionStateFlow, toScene = SceneKey.Bouncer) + assertThat(currentScene).isNotEqualTo(SceneKey.Lockscreen) + + kosmos.falsingManager.sendFalsingBelief() + + assertThat(currentScene).isEqualTo(SceneKey.Lockscreen) + } + private fun TestScope.emulateSceneTransition( transitionStateFlow: MutableStateFlow<ObservableTransitionState>, toScene: SceneKey, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt index 0641c610aaff..7f5a658587f3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt @@ -47,8 +47,6 @@ import com.android.systemui.res.R import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.mockLargeScreenHeaderHelper import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor -import com.android.systemui.statusbar.policy.SplitShadeStateController -import com.android.systemui.statusbar.policy.splitShadeStateController import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.whenever @@ -68,7 +66,6 @@ import org.mockito.Mockito.mock @RunWith(AndroidJUnit4::class) class SharedNotificationContainerViewModelTest : SysuiTestCase() { val aodBurnInViewModel = mock(AodBurnInViewModel::class.java) - val splitShadeStateController = mock(SplitShadeStateController::class.java) lateinit var translationYFlow: MutableStateFlow<Float> val kosmos = @@ -81,7 +78,6 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { init { kosmos.aodBurnInViewModel = aodBurnInViewModel - kosmos.splitShadeStateController = splitShadeStateController } val testScope = kosmos.testScope val configurationRepository = kosmos.fakeConfigurationRepository @@ -98,7 +94,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { @Before fun setUp() { - whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())).thenReturn(false) + overrideResource(R.bool.config_use_split_notification_shade, false) translationYFlow = MutableStateFlow(0f) whenever(aodBurnInViewModel.translationY(any())).thenReturn(translationYFlow) underTest = kosmos.sharedNotificationContainerViewModel @@ -107,8 +103,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { @Test fun validateMarginStartInSplitShade() = testScope.runTest { - whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) - .thenReturn(true) + overrideResource(R.bool.config_use_split_notification_shade, true) overrideResource(R.dimen.notification_panel_margin_horizontal, 20) val dimens by collectLastValue(underTest.configurationBasedDimensions) @@ -121,8 +116,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { @Test fun validateMarginStart() = testScope.runTest { - whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) - .thenReturn(false) + overrideResource(R.bool.config_use_split_notification_shade, false) overrideResource(R.dimen.notification_panel_margin_horizontal, 20) val dimens by collectLastValue(underTest.configurationBasedDimensions) @@ -137,8 +131,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { testScope.runTest { mSetFlagsRule.disableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX) whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5) - whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) - .thenReturn(true) + overrideResource(R.bool.config_use_split_notification_shade, true) overrideResource(R.bool.config_use_large_screen_shade_header, true) overrideResource(R.dimen.large_screen_shade_header_height, 10) overrideResource(R.dimen.keyguard_split_shade_top_margin, 50) @@ -156,8 +149,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { testScope.runTest { mSetFlagsRule.enableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX) whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5) - whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) - .thenReturn(true) + overrideResource(R.bool.config_use_split_notification_shade, true) overrideResource(R.bool.config_use_large_screen_shade_header, true) overrideResource(R.dimen.large_screen_shade_header_height, 10) overrideResource(R.dimen.keyguard_split_shade_top_margin, 50) @@ -172,8 +164,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { @Test fun validatePaddingTop() = testScope.runTest { - whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) - .thenReturn(false) + overrideResource(R.bool.config_use_split_notification_shade, false) overrideResource(R.dimen.large_screen_shade_header_height, 10) overrideResource(R.dimen.keyguard_split_shade_top_margin, 50) @@ -431,8 +422,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { val bounds by collectLastValue(underTest.bounds) // When not in split shade - whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) - .thenReturn(false) + overrideResource(R.bool.config_use_split_notification_shade, false) configurationRepository.onAnyConfigurationChange() runCurrent() @@ -454,8 +444,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { // When in split shade whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5) - whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) - .thenReturn(true) + overrideResource(R.bool.config_use_split_notification_shade, true) overrideResource(R.bool.config_use_large_screen_shade_header, true) overrideResource(R.dimen.large_screen_shade_header_height, 10) overrideResource(R.dimen.keyguard_split_shade_top_margin, 50) @@ -483,8 +472,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { // When in split shade whenever(largeScreenHeaderHelper.getLargeScreenHeaderHeight()).thenReturn(5) - whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) - .thenReturn(true) + overrideResource(R.bool.config_use_split_notification_shade, true) overrideResource(R.bool.config_use_large_screen_shade_header, true) overrideResource(R.dimen.large_screen_shade_header_height, 10) overrideResource(R.dimen.keyguard_split_shade_top_margin, 50) @@ -543,8 +531,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { showLockscreen() - whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) - .thenReturn(false) + overrideResource(R.bool.config_use_split_notification_shade, false) configurationRepository.onAnyConfigurationChange() keyguardInteractor.setNotificationContainerBounds( NotificationContainerBounds(top = 1f, bottom = 2f) @@ -567,8 +554,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { showLockscreen() - whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) - .thenReturn(false) + overrideResource(R.bool.config_use_split_notification_shade, false) configurationRepository.onAnyConfigurationChange() keyguardInteractor.setNotificationContainerBounds( NotificationContainerBounds(top = 1f, bottom = 2f) @@ -604,8 +590,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { // Show lockscreen with shade expanded showLockscreenWithShadeExpanded() - whenever(splitShadeStateController.shouldUseSplitNotificationShade(any())) - .thenReturn(false) + overrideResource(R.bool.config_use_split_notification_shade, false) configurationRepository.onAnyConfigurationChange() keyguardInteractor.setNotificationContainerBounds( NotificationContainerBounds(top = 1f, bottom = 2f) @@ -701,6 +686,32 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() { assertThat(fadeIn).isEqualTo(false) } + @Test + fun shadeCollapseFadeIn_doesNotRunIfTransitioningToAod() = + testScope.runTest { + val fadeIn by collectLastValue(underTest.shadeCollapseFadeIn) + + // Start on lockscreen without the shade + underTest.setShadeCollapseFadeInComplete(false) + showLockscreen() + assertThat(fadeIn).isEqualTo(false) + + // ... then the shade expands + showLockscreenWithShadeExpanded() + assertThat(fadeIn).isEqualTo(false) + + // ... then user hits power to go to AOD + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + testScope, + ) + // ... followed by a shade collapse + showLockscreen() + // ... does not trigger a fade in + assertThat(fadeIn).isEqualTo(false) + } + private suspend fun TestScope.showLockscreen() { shadeRepository.setLockscreenShadeExpansion(0f) shadeRepository.setQsExpansion(0f) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java index 87d25ddcc75c..6390e82321f0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java @@ -19,8 +19,6 @@ package com.android.systemui.statusbar.policy; import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED; import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; -import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED; -import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler; import static com.google.common.truth.Truth.assertThat; @@ -41,31 +39,23 @@ import android.app.ActivityManager; import android.app.Notification; import android.app.PendingIntent; import android.app.Person; -import android.content.Context; import android.content.Intent; -import android.graphics.Region; import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.testing.TestableLooper; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.test.filters.SmallTest; import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; -import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.testing.UiEventLoggerFake; import com.android.systemui.SysuiTestCase; import com.android.systemui.res.R; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.settings.FakeGlobalSettings; -import com.android.systemui.util.settings.GlobalSettings; import com.android.systemui.util.time.FakeSystemClock; -import com.android.systemui.util.time.SystemClock; import org.junit.Rule; import org.junit.Test; @@ -81,17 +71,13 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Rule public MockitoRule rule = MockitoJUnit.rule(); - private static final String TEST_PACKAGE_NAME = "BaseHeadsUpManagerTest"; - - private static final int TEST_TOUCH_ACCEPTANCE_TIME = 200; - private static final int TEST_A11Y_AUTO_DISMISS_TIME = 1_000; + static final int TEST_TOUCH_ACCEPTANCE_TIME = 200; + static final int TEST_A11Y_AUTO_DISMISS_TIME = 1_000; private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake(); private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer())); @Mock private AccessibilityManagerWrapper mAccessibilityMgr; - private static final int TEST_UID = 0; - protected static final int TEST_MINIMUM_DISPLAY_TIME = 400; protected static final int TEST_AUTO_DISMISS_TIME = 600; protected static final int TEST_STICKY_AUTO_DISMISS_TIME = 800; @@ -110,143 +96,6 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME); } - private final class TestableHeadsUpManager extends BaseHeadsUpManager { - - private HeadsUpEntry mLastCreatedEntry; - - TestableHeadsUpManager(Context context, - HeadsUpManagerLogger logger, - DelayableExecutor executor, - GlobalSettings globalSettings, - SystemClock systemClock, - AccessibilityManagerWrapper accessibilityManagerWrapper, - UiEventLogger uiEventLogger) { - super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock, - executor, accessibilityManagerWrapper, uiEventLogger); - - mTouchAcceptanceDelay = TEST_TOUCH_ACCEPTANCE_TIME; - mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME; - mAutoDismissTime = TEST_AUTO_DISMISS_TIME; - mStickyForSomeTimeAutoDismissTime = TEST_STICKY_AUTO_DISMISS_TIME; - - } - - @Override - protected HeadsUpEntry createHeadsUpEntry() { - mLastCreatedEntry = spy(super.createHeadsUpEntry()); - return mLastCreatedEntry; - } - - @Override - public int getContentFlag() { - return FLAG_CONTENT_VIEW_CONTRACTED; - } - - // The following are only implemented by HeadsUpManagerPhone. If you need them, use that. - @Override - public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) { - throw new UnsupportedOperationException(); - } - - @Override - public void addSwipedOutNotification(@NonNull String key) { - throw new UnsupportedOperationException(); - } - - @Override - public void extendHeadsUp() { - throw new UnsupportedOperationException(); - } - - @Nullable - @Override - public Region getTouchableRegion() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isHeadsUpGoingAway() { - throw new UnsupportedOperationException(); - } - - @Override - public void onExpandingFinished() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean removeNotification(@NonNull String key, boolean releaseImmediately, - boolean animate) { - throw new UnsupportedOperationException(); - } - - @Override - public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) { - throw new UnsupportedOperationException(); - } - - @Override - public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) { - throw new UnsupportedOperationException(); - } - - @Override - public void setHeadsUpGoingAway(boolean headsUpGoingAway) { - throw new UnsupportedOperationException(); - } - - @Override - public void setRemoteInputActive(@NonNull NotificationEntry entry, - boolean remoteInputActive) { - throw new UnsupportedOperationException(); - } - - @Override - public void setTrackingHeadsUp(boolean tracking) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean shouldSwallowClick(@NonNull String key) { - throw new UnsupportedOperationException(); - } - } - - protected StatusBarNotification createSbn(int id, Notification n) { - return new StatusBarNotification( - TEST_PACKAGE_NAME /* pkg */, - TEST_PACKAGE_NAME, - id, - null /* tag */, - TEST_UID, - 0 /* initialPid */, - n, - new UserHandle(ActivityManager.getCurrentUser()), - null /* overrideGroupKey */, - 0 /* postTime */); - } - - protected StatusBarNotification createSbn(int id, Notification.Builder n) { - return createSbn(id, n.build()); - } - - protected StatusBarNotification createSbn(int id) { - final Notification.Builder b = new Notification.Builder(mContext, "") - .setSmallIcon(R.drawable.ic_person) - .setContentTitle("Title") - .setContentText("Text"); - return createSbn(id, b); - } - - protected NotificationEntry createEntry(int id, Notification n) { - return new NotificationEntryBuilder().setSbn(createSbn(id, n)).build(); - } - - protected NotificationEntry createEntry(int id) { - return new NotificationEntryBuilder().setSbn(createSbn(id)).build(); - } - - private BaseHeadsUpManager createHeadsUpManager() { return new TestableHeadsUpManager(mContext, mLogger, mExecutor, mGlobalSettings, mSystemClock, mAccessibilityMgr, mUiEventLoggerFake); @@ -257,7 +106,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { .setSmallIcon(R.drawable.ic_person) .setFullScreenIntent(mock(PendingIntent.class), /* highPriority */ true) .build(); - return createEntry(id, notif); + return HeadsUpManagerTestUtil.createEntry(id, notif); } private NotificationEntry createStickyForSomeTimeEntry(int id) { @@ -265,7 +114,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { .setSmallIcon(R.drawable.ic_person) .setFlag(FLAG_FSI_REQUESTED_BUT_DENIED, true) .build(); - return createEntry(id, notif); + return HeadsUpManagerTestUtil.createEntry(id, notif); } private PendingIntent createFullScreenIntent() { @@ -279,7 +128,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { .setSmallIcon(R.drawable.ic_person) .setFullScreenIntent(createFullScreenIntent(), /* highPriority */ true) .build(); - return createEntry(id, notif); + return HeadsUpManagerTestUtil.createEntry(id, notif); } @@ -296,7 +145,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testShowNotification_addsEntry() { final BaseHeadsUpManager alm = createHeadsUpManager(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); alm.showNotification(entry); @@ -308,7 +157,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testShowNotification_autoDismisses() { final BaseHeadsUpManager alm = createHeadsUpManager(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); alm.showNotification(entry); mSystemClock.advanceTime(TEST_AUTO_DISMISS_TIME * 3 / 2); @@ -319,7 +168,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testRemoveNotification_removeDeferred() { final BaseHeadsUpManager alm = createHeadsUpManager(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); alm.showNotification(entry); @@ -332,7 +181,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testRemoveNotification_forceRemove() { final BaseHeadsUpManager alm = createHeadsUpManager(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); alm.showNotification(entry); @@ -346,7 +195,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { public void testReleaseAllImmediately() { final BaseHeadsUpManager alm = createHeadsUpManager(); for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) { - final NotificationEntry entry = createEntry(i); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(i, mContext); entry.setRow(mRow); alm.showNotification(entry); } @@ -359,7 +208,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testCanRemoveImmediately_notShownLongEnough() { final BaseHeadsUpManager alm = createHeadsUpManager(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); alm.showNotification(entry); @@ -370,7 +219,8 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testHunRemovedLogging() { final BaseHeadsUpManager hum = createHeadsUpManager(); - final NotificationEntry notifEntry = createEntry(/* id = */ 0); + final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, + mContext); final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = mock( BaseHeadsUpManager.HeadsUpEntry.class); headsUpEntry.mEntry = notifEntry; @@ -413,7 +263,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testShouldHeadsUpBecomePinned_noFSI_false() { final BaseHeadsUpManager hum = createHeadsUpManager(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); assertFalse(hum.shouldHeadsUpBecomePinned(entry)); } @@ -422,7 +272,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() { final BaseHeadsUpManager hum = createHeadsUpManager(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); useAccessibilityTimeout(false); hum.showNotification(entry); @@ -435,7 +285,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testShowNotification_autoDismissesWithDefaultTimeout() { final BaseHeadsUpManager hum = createHeadsUpManager(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); useAccessibilityTimeout(false); hum.showNotification(entry); @@ -476,7 +326,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testShowNotification_autoDismissesWithAccessibilityTimeout() { final BaseHeadsUpManager hum = createHeadsUpManager(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); useAccessibilityTimeout(true); hum.showNotification(entry); @@ -504,7 +354,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testRemoveNotification_beforeMinimumDisplayTime() { final BaseHeadsUpManager hum = createHeadsUpManager(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); useAccessibilityTimeout(false); hum.showNotification(entry); @@ -523,7 +373,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testRemoveNotification_afterMinimumDisplayTime() { final BaseHeadsUpManager hum = createHeadsUpManager(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); useAccessibilityTimeout(false); hum.showNotification(entry); @@ -541,7 +391,7 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testRemoveNotification_releaseImmediately() { final BaseHeadsUpManager hum = createHeadsUpManager(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); hum.showNotification(entry); @@ -555,7 +405,8 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testIsSticky_rowPinnedAndExpanded_true() { final BaseHeadsUpManager hum = createHeadsUpManager(); - final NotificationEntry notifEntry = createEntry(/* id = */ 0); + final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, + mContext); when(mRow.isPinned()).thenReturn(true); notifEntry.setRow(mRow); @@ -571,7 +422,8 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testIsSticky_remoteInputActive_true() { final BaseHeadsUpManager hum = createHeadsUpManager(); - final NotificationEntry notifEntry = createEntry(/* id = */ 0); + final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, + mContext); hum.showNotification(notifEntry); @@ -607,7 +459,8 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testIsSticky_false() { final BaseHeadsUpManager hum = createHeadsUpManager(); - final NotificationEntry notifEntry = createEntry(/* id = */ 0); + final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, + mContext); hum.showNotification(notifEntry); @@ -653,14 +506,14 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { final BaseHeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry(); ongoingCall.setEntry(new NotificationEntryBuilder() - .setSbn(createSbn(/* id = */ 0, + .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0, new Notification.Builder(mContext, "") .setCategory(Notification.CATEGORY_CALL) .setOngoing(true))) .build()); final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry(); - activeRemoteInput.setEntry(createEntry(/* id = */ 1)); + activeRemoteInput.setEntry(HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext)); activeRemoteInput.mRemoteInputActive = true; assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0); @@ -675,14 +528,14 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { final Person person = new Person.Builder().setName("person").build(); final PendingIntent intent = mock(PendingIntent.class); incomingCall.setEntry(new NotificationEntryBuilder() - .setSbn(createSbn(/* id = */ 0, + .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0, new Notification.Builder(mContext, "") .setStyle(Notification.CallStyle .forIncomingCall(person, intent, intent)))) .build()); final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry(); - activeRemoteInput.setEntry(createEntry(/* id = */ 1)); + activeRemoteInput.setEntry(HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext)); activeRemoteInput.mRemoteInputActive = true; assertThat(incomingCall.compareTo(activeRemoteInput)).isLessThan(0); @@ -712,7 +565,8 @@ public class BaseHeadsUpManagerTest extends SysuiTestCase { @Test public void testSetUserActionMayIndirectlyRemove() { final BaseHeadsUpManager hum = createHeadsUpManager(); - final NotificationEntry notifEntry = createEntry(/* id = */ 0); + final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, + mContext); hum.showNotification(notifEntry); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java index c350de21dda5..ec23f76935d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.phone; +package com.android.systemui.statusbar.policy; import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer; import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler; @@ -26,10 +26,10 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.when; import android.content.Context; -import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import androidx.test.filters.SmallTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.internal.logging.UiEventLogger; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -39,11 +39,9 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; -import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper; -import com.android.systemui.statusbar.policy.BaseHeadsUpManagerTest; -import com.android.systemui.statusbar.policy.ConfigurationController; -import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.statusbar.policy.HeadsUpManagerLogger; +import com.android.systemui.statusbar.phone.ConfigurationControllerImpl; +import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; +import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.util.concurrency.DelayableExecutor; import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.settings.GlobalSettings; @@ -61,7 +59,7 @@ import org.mockito.junit.MockitoRule; import kotlinx.coroutines.flow.StateFlowKt; @SmallTest -@RunWith(AndroidTestingRunner.class) +@RunWith(AndroidJUnit4.class) @TestableLooper.RunWithLooper public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest { @Rule public MockitoRule rule = MockitoJUnit.rule(); @@ -152,7 +150,7 @@ public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest { @Test public void testSnooze() { final HeadsUpManager hmp = createHeadsUpManagerPhone(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); hmp.showNotification(entry); hmp.snooze(); @@ -163,7 +161,7 @@ public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest { @Test public void testSwipedOutNotification() { final HeadsUpManager hmp = createHeadsUpManagerPhone(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); hmp.showNotification(entry); hmp.addSwipedOutNotification(entry.getKey()); @@ -179,7 +177,7 @@ public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest { @Test public void testCanRemoveImmediately_swipedOut() { final HeadsUpManager hmp = createHeadsUpManagerPhone(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); hmp.showNotification(entry); hmp.addSwipedOutNotification(entry.getKey()); @@ -192,8 +190,10 @@ public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest { @Test public void testCanRemoveImmediately_notTopEntry() { final HeadsUpManager hmp = createHeadsUpManagerPhone(); - final NotificationEntry earlierEntry = createEntry(/* id = */ 0); - final NotificationEntry laterEntry = createEntry(/* id = */ 1); + final NotificationEntry earlierEntry = + HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); + final NotificationEntry laterEntry = + HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext); laterEntry.setRow(mRow); hmp.showNotification(earlierEntry); @@ -206,7 +206,7 @@ public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest { @Test public void testExtendHeadsUp() { final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone(); - final NotificationEntry entry = createEntry(/* id = */ 0); + final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext); hmp.showNotification(entry); hmp.extendHeadsUp(); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java new file mode 100644 index 000000000000..c70b03b08789 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; +import android.app.ActivityManager; +import android.os.UserHandle; + +import android.content.Context; +import android.service.notification.StatusBarNotification; +import android.app.Notification; + +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; + +/** + * Test helper class for HeadsUpEntry creation. + */ +public class HeadsUpManagerTestUtil { + + private static final String TEST_PACKAGE_NAME = "HeadsUpManagerTestUtil"; + private static final int TEST_UID = 0; + + protected static StatusBarNotification createSbn(int id, Notification.Builder n) { + return createSbn(id, n.build()); + } + + protected static StatusBarNotification createSbn(int id, Context context) { + final Notification.Builder b = new Notification.Builder(context, "") + .setSmallIcon(com.android.systemui.res.R.drawable.ic_person) + .setContentTitle("Title") + .setContentText("Text"); + return createSbn(id, b); + } + + protected static StatusBarNotification createSbn(int id, Notification n) { + return new StatusBarNotification( + TEST_PACKAGE_NAME /* pkg */, + TEST_PACKAGE_NAME, + id, + null /* tag */, + TEST_UID, + 0 /* initialPid */, + n, + new UserHandle(ActivityManager.getCurrentUser()), + null /* overrideGroupKey */, + 0 /* postTime */); + } + + protected static NotificationEntry createEntry(int id, Notification n) { + return new NotificationEntryBuilder().setSbn(createSbn(id, n)).build(); + } + + protected static NotificationEntry createEntry(int id, Context context) { + return new NotificationEntryBuilder().setSbn( + HeadsUpManagerTestUtil.createSbn(id, context)).build(); + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java new file mode 100644 index 000000000000..27476299cf18 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.policy; + +import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED; +import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler; + +import static org.mockito.Mockito.spy; + +import android.content.Context; +import android.graphics.Region; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.internal.logging.UiEventLogger; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.util.concurrency.DelayableExecutor; +import com.android.systemui.util.settings.GlobalSettings; +import com.android.systemui.util.time.SystemClock; + +class TestableHeadsUpManager extends BaseHeadsUpManager { + + private HeadsUpEntry mLastCreatedEntry; + + TestableHeadsUpManager(Context context, + HeadsUpManagerLogger logger, + DelayableExecutor executor, + GlobalSettings globalSettings, + SystemClock systemClock, + AccessibilityManagerWrapper accessibilityManagerWrapper, + UiEventLogger uiEventLogger) { + super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock, + executor, accessibilityManagerWrapper, uiEventLogger); + + mTouchAcceptanceDelay = BaseHeadsUpManagerTest.TEST_TOUCH_ACCEPTANCE_TIME; + mMinimumDisplayTime = BaseHeadsUpManagerTest.TEST_MINIMUM_DISPLAY_TIME; + mAutoDismissTime = BaseHeadsUpManagerTest.TEST_AUTO_DISMISS_TIME; + mStickyForSomeTimeAutoDismissTime = BaseHeadsUpManagerTest.TEST_STICKY_AUTO_DISMISS_TIME; + } + + @Override + protected HeadsUpEntry createHeadsUpEntry() { + mLastCreatedEntry = spy(super.createHeadsUpEntry()); + return mLastCreatedEntry; + } + + @Override + public int getContentFlag() { + return FLAG_CONTENT_VIEW_CONTRACTED; + } + + // The following are only implemented by HeadsUpManagerPhone. If you need them, use that. + @Override + public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) { + throw new UnsupportedOperationException(); + } + + @Override + public void addSwipedOutNotification(@NonNull String key) { + throw new UnsupportedOperationException(); + } + + @Override + public void extendHeadsUp() { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public Region getTouchableRegion() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isHeadsUpGoingAway() { + throw new UnsupportedOperationException(); + } + + @Override + public void onExpandingFinished() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeNotification(@NonNull String key, boolean releaseImmediately, + boolean animate) { + throw new UnsupportedOperationException(); + } + + @Override + public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) { + throw new UnsupportedOperationException(); + } + + @Override + public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) { + throw new UnsupportedOperationException(); + } + + @Override + public void setHeadsUpGoingAway(boolean headsUpGoingAway) { + throw new UnsupportedOperationException(); + } + + @Override + public void setRemoteInputActive(@NonNull NotificationEntry entry, + boolean remoteInputActive) { + throw new UnsupportedOperationException(); + } + + @Override + public void setTrackingHeadsUp(boolean tracking) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean shouldSwallowClick(@NonNull String key) { + throw new UnsupportedOperationException(); + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/ClientTrackingWakeLockTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/ClientTrackingWakeLockTest.kt new file mode 100644 index 000000000000..fdfcdc486c02 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/wakelock/ClientTrackingWakeLockTest.kt @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.wakelock + +import android.os.Build +import android.os.PowerManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import org.junit.After +import org.junit.Assert +import org.junit.Assume +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class ClientTrackingWakeLockTest : SysuiTestCase() { + + private val WHY = "test" + private val WHY_2 = "test2" + + lateinit var mWakeLock: ClientTrackingWakeLock + lateinit var mInner: PowerManager.WakeLock + + @Before + fun setUp() { + mInner = + WakeLock.createWakeLockInner(mContext, "WakeLockTest", PowerManager.PARTIAL_WAKE_LOCK) + mWakeLock = ClientTrackingWakeLock(mInner, null, 20000) + } + + @After + fun tearDown() { + mInner.setReferenceCounted(false) + mInner.release() + } + + @Test + fun createPartialInner_notHeldYet() { + Assert.assertFalse(mInner.isHeld) + } + + @Test + fun wakeLock_acquire() { + mWakeLock.acquire(WHY) + Assert.assertTrue(mInner.isHeld) + } + + @Test + fun wakeLock_release() { + mWakeLock.acquire(WHY) + mWakeLock.release(WHY) + Assert.assertFalse(mInner.isHeld) + } + + @Test + fun wakeLock_acquiredReleasedMultipleSources_stillHeld() { + mWakeLock.acquire(WHY) + mWakeLock.acquire(WHY_2) + mWakeLock.release(WHY) + + Assert.assertTrue(mInner.isHeld) + mWakeLock.release(WHY_2) + Assert.assertFalse(mInner.isHeld) + } + + @Test + fun wakeLock_releasedTooManyTimes_stillReleased_noThrow() { + Assume.assumeFalse(Build.IS_ENG) + mWakeLock.acquire(WHY) + mWakeLock.acquire(WHY_2) + mWakeLock.release(WHY) + mWakeLock.release(WHY_2) + mWakeLock.release(WHY) + Assert.assertFalse(mInner.isHeld) + } + + @Test + fun wakeLock_wrap() { + val ran = BooleanArray(1) + val wrapped = mWakeLock.wrap { ran[0] = true } + Assert.assertTrue(mInner.isHeld) + Assert.assertFalse(ran[0]) + wrapped.run() + Assert.assertTrue(ran[0]) + Assert.assertFalse(mInner.isHeld) + } + + @Test + fun prodBuild_wakeLock_releaseWithoutAcquire_noThrow() { + Assume.assumeFalse(Build.IS_ENG) + // shouldn't throw an exception on production builds + mWakeLock.release(WHY) + } + + @Test + fun acquireSeveralLocks_stringReportsCorrectCount() { + mWakeLock.acquire(WHY) + mWakeLock.acquire(WHY_2) + mWakeLock.acquire(WHY) + mWakeLock.acquire(WHY) + mWakeLock.acquire(WHY_2) + Assert.assertEquals(5, mWakeLock.activeClients()) + + mWakeLock.release(WHY_2) + mWakeLock.release(WHY_2) + Assert.assertEquals(3, mWakeLock.activeClients()) + + mWakeLock.release(WHY) + mWakeLock.release(WHY) + mWakeLock.release(WHY) + Assert.assertEquals(0, mWakeLock.activeClients()) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt new file mode 100644 index 000000000000..737b7f3e0af0 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.spatial + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import com.android.systemui.media.spatializerInteractor +import com.android.systemui.volume.mediaOutputInteractor +import com.android.systemui.volume.panel.component.spatial.domain.interactor.SpatialAudioComponentInteractor + +val Kosmos.spatialAudioComponentInteractor by + Kosmos.Fixture { + SpatialAudioComponentInteractor( + mediaOutputInteractor, + spatializerInteractor, + testScope.backgroundScope + ) + } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt new file mode 100644 index 000000000000..36be90ecbf7e --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.spatial.domain + +import android.media.session.MediaSession +import android.media.session.PlaybackState +import android.testing.TestableLooper.RunWithLooper +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.settingslib.bluetooth.CachedBluetoothDevice +import com.android.settingslib.media.BluetoothMediaDevice +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testScope +import com.android.systemui.media.spatializerRepository +import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.android.systemui.volume.localMediaRepository +import com.android.systemui.volume.mediaController +import com.android.systemui.volume.mediaControllerRepository +import com.android.systemui.volume.panel.component.spatial.spatialAudioComponentInteractor +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +@RunWithLooper(setAsMainLooper = true) +class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() { + + private val kosmos = testKosmos() + private val cachedBluetoothDevice: CachedBluetoothDevice = mock { + whenever(address).thenReturn("test_address") + } + private val bluetoothMediaDevice: BluetoothMediaDevice = mock { + whenever(cachedDevice).thenReturn(cachedBluetoothDevice) + } + + private lateinit var underTest: SpatialAudioAvailabilityCriteria + + @Before + fun setup() { + with(kosmos) { + mediaControllerRepository.setActiveLocalMediaController( + mediaController.apply { + whenever(packageName).thenReturn("test.pkg") + whenever(sessionToken).thenReturn(MediaSession.Token(0, mock {})) + whenever(playbackState).thenReturn(PlaybackState.Builder().build()) + } + ) + + underTest = SpatialAudioAvailabilityCriteria(spatialAudioComponentInteractor) + } + } + + @Test + fun noSpatialAudio_noHeadTracking_unavailable() { + with(kosmos) { + testScope.runTest { + localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice) + spatializerRepository.setIsHeadTrackingAvailable(false) + spatializerRepository.defaultSpatialAudioAvailable = false + + val isAvailable by collectLastValue(underTest.isAvailable()) + runCurrent() + + assertThat(isAvailable).isFalse() + } + } + } + + @Test + fun spatialAudio_noHeadTracking_available() { + with(kosmos) { + testScope.runTest { + localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice) + spatializerRepository.setIsHeadTrackingAvailable(false) + spatializerRepository.defaultSpatialAudioAvailable = true + + val isAvailable by collectLastValue(underTest.isAvailable()) + runCurrent() + + assertThat(isAvailable).isTrue() + } + } + } + + @Test + fun spatialAudio_headTracking_available() { + with(kosmos) { + testScope.runTest { + localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice) + spatializerRepository.setIsHeadTrackingAvailable(true) + spatializerRepository.defaultSpatialAudioAvailable = true + + val isAvailable by collectLastValue(underTest.isAvailable()) + runCurrent() + + assertThat(isAvailable).isTrue() + } + } + } + + @Test + fun spatialAudio_headTracking_noDevice_unavailable() { + with(kosmos) { + testScope.runTest { + spatializerRepository.setIsHeadTrackingAvailable(true) + spatializerRepository.defaultSpatialAudioAvailable = true + + val isAvailable by collectLastValue(underTest.isAvailable()) + runCurrent() + + assertThat(isAvailable).isFalse() + } + } + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt new file mode 100644 index 000000000000..eb6f0b2e32b3 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.spatial.domain.interactor + +import android.media.AudioDeviceAttributes +import android.media.AudioDeviceInfo +import android.media.session.MediaSession +import android.media.session.PlaybackState +import android.testing.TestableLooper +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.settingslib.bluetooth.CachedBluetoothDevice +import com.android.settingslib.media.BluetoothMediaDevice +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectValues +import com.android.systemui.kosmos.testScope +import com.android.systemui.media.spatializerInteractor +import com.android.systemui.media.spatializerRepository +import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever +import com.android.systemui.volume.localMediaRepository +import com.android.systemui.volume.mediaController +import com.android.systemui.volume.mediaControllerRepository +import com.android.systemui.volume.mediaOutputInteractor +import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +class SpatialAudioComponentInteractorTest : SysuiTestCase() { + + private val kosmos = testKosmos() + private lateinit var underTest: SpatialAudioComponentInteractor + + @Before + fun setup() { + with(kosmos) { + val cachedBluetoothDevice: CachedBluetoothDevice = mock { + whenever(address).thenReturn("test_address") + } + localMediaRepository.updateCurrentConnectedDevice( + mock<BluetoothMediaDevice> { + whenever(name).thenReturn("test_device") + whenever(cachedDevice).thenReturn(cachedBluetoothDevice) + } + ) + + whenever(mediaController.packageName).thenReturn("test.pkg") + whenever(mediaController.sessionToken).thenReturn(MediaSession.Token(0, mock {})) + whenever(mediaController.playbackState).thenReturn(PlaybackState.Builder().build()) + + mediaControllerRepository.setActiveLocalMediaController(mediaController) + + spatializerRepository.setIsSpatialAudioAvailable( + AudioDeviceAttributes( + AudioDeviceAttributes.ROLE_OUTPUT, + AudioDeviceInfo.TYPE_BLE_HEADSET, + "test_address" + ), + true + ) + spatializerRepository.setIsHeadTrackingAvailable(true) + + underTest = + SpatialAudioComponentInteractor( + mediaOutputInteractor, + spatializerInteractor, + testScope.backgroundScope, + ) + } + } + + @Test + fun setEnabled_changesIsEnabled() { + with(kosmos) { + testScope.runTest { + val values by collectValues(underTest.isEnabled) + + underTest.setEnabled(SpatialAudioEnabledModel.Disabled) + runCurrent() + underTest.setEnabled(SpatialAudioEnabledModel.HeadTrackingEnabled) + runCurrent() + underTest.setEnabled(SpatialAudioEnabledModel.SpatialAudioEnabled) + runCurrent() + + assertThat(values) + .containsExactly( + SpatialAudioEnabledModel.Disabled, + SpatialAudioEnabledModel.HeadTrackingEnabled, + SpatialAudioEnabledModel.SpatialAudioEnabled, + ) + .inOrder() + } + } + } +} diff --git a/packages/SystemUI/res/drawable/battery_unified_attr_charging.xml b/packages/SystemUI/res/drawable/battery_unified_attr_charging.xml new file mode 100644 index 000000000000..8e3b89b9a7eb --- /dev/null +++ b/packages/SystemUI/res/drawable/battery_unified_attr_charging.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="8dp" + android:height="10dp" + android:viewportWidth="16.0" + android:viewportHeight="20.0"> + <path + android:pathData="M4,20L5,13H0L9,0H11L10,8H16L6,20H4Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SystemUI/res/drawable/battery_unified_attr_defend.xml b/packages/SystemUI/res/drawable/battery_unified_attr_defend.xml new file mode 100644 index 000000000000..e7beee2bc7c0 --- /dev/null +++ b/packages/SystemUI/res/drawable/battery_unified_attr_defend.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="8dp" + android:height="9dp" + android:viewportWidth="8.0" + android:viewportHeight="9.0"> + <path + android:pathData="M3.698,9C2.629,8.765 1.746,8.181 1.048,7.247C0.349,6.306 0,5.266 0,4.126V1.422L3.698,0L7.397,1.422V4.126C7.397,5.266 7.048,6.306 6.349,7.247C5.651,8.181 4.767,8.765 3.698,9ZM3.698,7.846C4.439,7.596 5.052,7.129 5.537,6.445C6.029,5.754 6.274,4.981 6.274,4.126V2.191L3.698,1.197L1.122,2.191V4.126C1.122,4.981 1.365,5.754 1.849,6.445C2.341,7.129 2.957,7.596 3.698,7.846ZM3.698,7.183C3.1,6.99 2.605,6.616 2.213,6.061C1.828,5.505 1.635,4.888 1.635,4.211V2.651L3.698,1.86L5.761,2.651V4.211C5.761,4.888 5.565,5.505 5.173,6.061C4.789,6.616 4.297,6.99 3.698,7.183Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SystemUI/res/drawable/battery_unified_attr_powersave.xml b/packages/SystemUI/res/drawable/battery_unified_attr_powersave.xml new file mode 100644 index 000000000000..a2c0cbae3e8a --- /dev/null +++ b/packages/SystemUI/res/drawable/battery_unified_attr_powersave.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<!-- This drawable is inset for now until the unified battery attrs can get their own paddings --> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:insetRight="0.5dp" + > + <vector + android:width="8dp" + android:height="8dp" + android:viewportWidth="8.0" + android:viewportHeight="8.0" + > + <path + android:pathData="M3.242,4.758H0V3.257H3.242V0H4.758V3.257H8V4.758H4.758V8.015H3.242V4.758Z" + android:fillColor="#000"/> + </vector> +</inset> diff --git a/packages/SystemUI/res/drawable/battery_unified_frame.xml b/packages/SystemUI/res/drawable/battery_unified_frame.xml new file mode 100644 index 000000000000..016b88b5cca1 --- /dev/null +++ b/packages/SystemUI/res/drawable/battery_unified_frame.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<!-- Unified battery frame for BatteryLayersDrawable.kt --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="14dp" + android:viewportWidth="24.0" + android:viewportHeight="14.0"> + <!-- body --> + <path + android:pathData="@string/battery_unified_frame_path_string" + android:strokeColor="#000" + android:strokeWidth="1.5" + /> + <!-- cap --> + <path + android:pathData="M0,4C0,3.448 0.448,3 1,3H1.5V11H1C0.448,11 0,10.552 0,10V4Z" + android:fillColor="#000"/> +</vector> diff --git a/packages/SystemUI/res/drawable/battery_unified_frame_bg.xml b/packages/SystemUI/res/drawable/battery_unified_frame_bg.xml new file mode 100644 index 000000000000..8e04f109fade --- /dev/null +++ b/packages/SystemUI/res/drawable/battery_unified_frame_bg.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<!-- Vector description of the battery gutter: the background of the fill --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="14dp" + android:viewportWidth="24.0" + android:viewportHeight="14.0"> + <path + android:pathData="@string/battery_unified_frame_path_string" + android:fillColor="#fff" /> +</vector> diff --git a/packages/SystemUI/res/drawable/bg_shutdown_finder_message.xml b/packages/SystemUI/res/drawable/bg_shutdown_finder_message.xml new file mode 100644 index 000000000000..324ae0c5c1d4 --- /dev/null +++ b/packages/SystemUI/res/drawable/bg_shutdown_finder_message.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <corners android:radius="28dp" /> + <solid android:color="@color/global_actions_lite_button_background" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/ic_finder_active.xml b/packages/SystemUI/res/drawable/ic_finder_active.xml new file mode 100644 index 000000000000..8ca221ab7392 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_finder_active.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,0L12,0A12,12 0,0 1,24 12L24,12A12,12 0,0 1,12 24L12,24A12,12 0,0 1,0 12L0,12A12,12 0,0 1,12 0z" + android:fillColor="#00677D"/> + <path + android:pathData="M12.797,4.005C11.949,3.936 11.203,4.597 11.203,5.467V6.659C8.855,7.001 6.998,8.856 6.653,11.203H5.467C4.597,11.203 3.936,11.948 4.005,12.796L4.006,12.802L4.006,12.809C4.38,16.605 7.399,19.625 11.195,20C12.051,20.087 12.803,19.404 12.803,18.547V17.355C15.154,17.012 17.013,15.154 17.355,12.803H18.54C19.406,12.803 20.079,12.058 19.992,11.196C19.618,7.4 16.606,4.388 12.812,4.006L12.804,4.006L12.797,4.005ZM11.203,9.344V8.283C9.741,8.591 8.588,9.741 8.278,11.203H9.344C9.585,10.4 10.179,9.754 10.942,9.437C11.027,9.402 11.114,9.371 11.203,9.344ZM11.998,13.171C11.358,13.175 10.828,12.651 10.827,12.004H10.827C10.827,11.959 10.83,11.915 10.835,11.871C10.885,11.427 11.185,11.056 11.59,10.902C11.694,10.863 11.806,10.838 11.921,10.83C11.948,10.833 11.976,10.834 12.003,10.834C12.65,10.834 13.177,11.356 13.179,12.007C13.177,12.622 12.695,13.13 12.091,13.175C12.06,13.172 12.029,13.17 11.998,13.171ZM17.353,11.203H18.383C18.028,8.289 15.72,5.979 12.804,5.616V6.658C15.153,7 17.004,8.852 17.353,11.203ZM14.663,11.203C14.395,10.311 13.692,9.611 12.804,9.344V8.283C14.265,8.59 15.414,9.736 15.727,11.203H14.663ZM5.615,12.803H6.654C7.001,15.15 8.855,17.002 11.203,17.346V18.391C8.287,18.034 5.972,15.719 5.615,12.803ZM11.203,14.666C10.316,14.394 9.613,13.692 9.345,12.803H8.279C8.591,14.264 9.741,15.412 11.203,15.721V14.666ZM14.661,12.811H15.729C15.418,14.272 14.266,15.422 12.804,15.73V14.662C13.689,14.396 14.391,13.699 14.661,12.811Z" + android:fillColor="#ffffff" + android:fillType="evenOdd"/> +</vector> diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml index 1365a11d7a56..22d156da7580 100644 --- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -263,8 +263,9 @@ android:layout_gravity="center_vertical|start"> <ImageView android:id="@+id/wifi_connected_icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scaleType="fitCenter" android:layout_gravity="center"/> </FrameLayout> diff --git a/packages/SystemUI/res/layout/internet_list_item.xml b/packages/SystemUI/res/layout/internet_list_item.xml index f6a213662a18..0da0f2b1e9b1 100644 --- a/packages/SystemUI/res/layout/internet_list_item.xml +++ b/packages/SystemUI/res/layout/internet_list_item.xml @@ -35,8 +35,9 @@ android:layout_gravity="center_vertical|start"> <ImageView android:id="@+id/wifi_icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scaleType="fitCenter" android:layout_gravity="center"/> </FrameLayout> diff --git a/packages/SystemUI/res/layout/shutdown_dialog_finder_active.xml b/packages/SystemUI/res/layout/shutdown_dialog_finder_active.xml new file mode 100644 index 000000000000..b6db7fc8007f --- /dev/null +++ b/packages/SystemUI/res/layout/shutdown_dialog_finder_active.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <TextView + android:id="@android:id/text1" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="24dp" + android:fontFamily="google-sans" + android:gravity="center" + android:text="@string/shutdown_progress" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textDirection="locale" + android:textSize="18sp" + android:visibility="gone" + app:layout_constraintBottom_toTopOf="@android:id/text2" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.375" + app:layout_constraintVertical_chainStyle="packed" /> + + <TextView + android:id="@android:id/text2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="24dp" + android:fontFamily="google-sans" + android:gravity="center" + android:text="@string/shutdown_progress" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textDirection="locale" + android:textSize="24sp" + app:layout_constraintBottom_toTopOf="@android:id/progress" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@android:id/text1" /> + + <ProgressBar + android:id="@android:id/progress" + style="?android:attr/progressBarStyleLarge" + android:layout_width="30dp" + android:layout_height="30dp" + android:importantForAccessibility="no" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@android:id/text2" /> + + <TextView + android:id="@+id/finer_hint" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="32dp" + android:background="@drawable/bg_shutdown_finder_message" + android:drawablePadding="16dp" + android:drawableStart="@drawable/ic_finder_active" + android:fontFamily="google-sans" + android:gravity="start" + android:padding="20dp" + android:text="@string/finder_active" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="@android:color/secondary_text_dark" + android:textDirection="locale" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@android:id/progress" + app:layout_constraintVertical_bias="1" /> +</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 5436642dc5a1..b7eff38aa015 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -164,6 +164,9 @@ so the width of the icon should be 13.0sp * (12.0 / 20.0) --> <dimen name="status_bar_battery_icon_width">7.8sp</dimen> + <dimen name="status_bar_battery_unified_icon_width">24sp</dimen> + <dimen name="status_bar_battery_unified_icon_height">14sp</dimen> + <!-- The battery icon is 13sp tall, but the other system icons are 15sp tall (see @*android:dimen/status_bar_system_icon_size) with some top and bottom padding embedded in the drawables themselves. So, the battery icon may need an extra 1dp of spacing so that its @@ -199,6 +202,7 @@ <!-- Size of the view displaying the mobile signal icon in the status bar. This value should match the core/status_bar_system_icon_size and change to sp unit --> <dimen name="status_bar_mobile_signal_size">15sp</dimen> + <dimen name="status_bar_mobile_signal_size_updated">14sp</dimen> <!-- Size of the view displaying the mobile signal icon in the status bar. This value should match the viewport height of mobile signal drawables such as ic_lte_mobiledata --> <dimen name="status_bar_mobile_type_size">16sp</dimen> @@ -898,8 +902,8 @@ <dimen name="communal_enforced_rounded_corner_max_radius">16dp</dimen> <!-- Width and height used to filter widgets displayed in the communal widget picker --> - <dimen name="communal_widget_picker_desired_width">464dp</dimen> - <dimen name="communal_widget_picker_desired_height">307dp</dimen> + <dimen name="communal_widget_picker_desired_width">424dp</dimen> + <dimen name="communal_widget_picker_desired_height">282dp</dimen> <!-- The width/height of the unlock icon view on keyguard. --> <dimen name="keyguard_lock_height">42dp</dimen> @@ -1518,6 +1522,12 @@ <!-- GLANCEABLE_HUB -> LOCKSCREEN transition: Amount to shift lockscreen content on entering --> <dimen name="hub_to_lockscreen_transition_lockscreen_translation_x">824dp</dimen> + <!-- DREAMING -> GLANCEABLE_HUB transition: Amount to shift dream overlay on entering --> + <dimen name="dreaming_to_hub_transition_dream_overlay_translation_x">-824dp</dimen> + + <!-- GLANCEABLE_HUB -> DREAMING transition: Amount to shift dream overlay on entering --> + <dimen name="hub_to_dreaming_transition_dream_overlay_translation_x">824dp</dimen> + <!-- Distance that the full shade transition takes in order for media to fully transition to the shade --> <dimen name="lockscreen_shade_media_transition_distance">120dp</dimen> @@ -1736,12 +1746,18 @@ <dimen name="communal_grid_height">630dp</dimen> <!-- Number of columns for each communal card --> <integer name="communal_grid_columns_per_card">6</integer> - <!-- Width of area on right edge of screen in which swipes will open the communal hub --> - <dimen name="communal_right_edge_swipe_region_width">16dp</dimen> + + <!-- The width of the swipe target to initiate opening or closing communal hub. --> + <dimen name="communal_gesture_initiation_width">68dp</dimen> + + <!-- TODO(b/322549765): unify with communal_gesture_initiation_width --> + <!-- Width of area on right edge of screen in which swipes will open the communal hub when on + the lockscreen --> + <dimen name="communal_right_edge_swipe_region_width">40dp</dimen> <!-- Height of area at top of communal hub where swipes should open the notification shade --> - <dimen name="communal_top_edge_swipe_region_height">32dp</dimen> + <dimen name="communal_top_edge_swipe_region_height">68dp</dimen> <!-- Height of area at bottom of communal hub where swipes should open the bouncer --> - <dimen name="communal_bottom_edge_swipe_region_height">32dp</dimen> + <dimen name="communal_bottom_edge_swipe_region_height">68dp</dimen> <dimen name="drag_and_drop_icon_size">70dp</dimen> @@ -1813,9 +1829,6 @@ <dimen name="dream_overlay_complication_smartspace_padding">24dp</dimen> <dimen name="dream_overlay_complication_smartspace_max_width">408dp</dimen> - <!-- The width of the swipe target to initiate opening communal hub over dreams. --> - <dimen name="communal_gesture_initiation_width">48dp</dimen> - <!-- The position of the end guide, which dream overlay complications can align their start with if their end is aligned with the parent end. Represented as the percentage over from the start of the parent container. --> @@ -1861,7 +1874,6 @@ <dimen name="dream_overlay_y_offset">80dp</dimen> <dimen name="dream_overlay_entry_y_offset">40dp</dimen> <dimen name="dream_overlay_exit_y_offset">40dp</dimen> - <dimen name="dream_overlay_exit_x_offset">824dp</dimen> <dimen name="status_view_margin_horizontal">0dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 4263d9402d66..346bdfc8b2d8 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -34,6 +34,10 @@ remaining [CHAR LIMIT=none]--> <string name="battery_low_percent_format"><xliff:g id="percentage">%s</xliff:g> remaining</string> + <!-- SVG path description for the battery frame of the unified battery drawable + (BatteryLayersDrawable.kt). Drawn on a 24x14 canvas. Not suitable outside in any other context --> + <string name="battery_unified_frame_path_string" translatable="false">M2.75,3C2.75,1.757 3.757,0.75 5,0.75H20C21.795,0.75 23.25,2.205 23.25,4V10C23.25,11.795 21.795,13.25 20,13.25H5C3.757,13.25 2.75,12.243 2.75,11V3Z </string> + <!-- A message that appears when the battery remaining estimate is low in a dialog. This is appended to the subtitle of the low battery alert. "percentage" is the percentage of battery remaining. "time" is the amount of time remaining before the phone runs out of battery [CHAR LIMIT=none]--> @@ -1114,6 +1118,8 @@ <string name="popup_on_dismiss_cta_tile_text">Long press to customize widgets</string> <!-- Text for the button to configure widgets after long press. [CHAR LIMIT=50] --> <string name="button_to_configure_widgets_text">Customize widgets</string> + <!-- Description for the App icon of disabled widget. [CHAR LIMIT=NONE] --> + <string name="icon_description_for_disabled_widget">App icon for disabled widget</string> <!-- Label for the button which configures widgets [CHAR LIMIT=NONE] --> <string name="edit_widget">Edit widget</string> <!-- Description for the button that removes a widget on click. [CHAR LIMIT=50] --> @@ -2236,6 +2242,11 @@ <!-- Tuner string --> <!-- Tuner string --> + <!-- Message shown during shutdown when Find My Device with Dead Battery Finder is active [CHAR LIMIT=300] --> + <string name="finder_active">You can locate this phone with Find My Device even when powered off</string> + <!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. [CHAR LIMIT=60] --> + <string name="shutdown_progress">Shutting down\u2026</string> + <!-- Text help link for care instructions for overheating devices [CHAR LIMIT=40] --> <string name="thermal_shutdown_dialog_help_text">See care steps</string> <!-- URL for care instructions for overheating devices --> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index 10393cf83247..ca63483f656a 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -196,7 +196,7 @@ public class ActivityManagerWrapper { final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback, Handler resultCallbackHandler) { boolean result = startRecentsActivity(intent, eventTime, animationHandler); - if (resultCallback != null) { + if (resultCallback != null && resultCallbackHandler != null) { resultCallbackHandler.post(new Runnable() { @Override public void run() { diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java index 1cfa816f4612..75cace424e8b 100644 --- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java +++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java @@ -17,9 +17,9 @@ package com.android.keyguard; import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_ACTIVE_DATA_SUB_CHANGED; -import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_ON_SIM_STATE_CHANGED; import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_ON_TELEPHONY_CAPABLE; import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_REFRESH_CARRIER_INFO; +import static com.android.keyguard.logging.CarrierTextManagerLogger.REASON_SIM_ERROR_STATE_CHANGED; import android.content.Context; import android.content.Intent; @@ -123,12 +123,15 @@ public class CarrierTextManager { return; } - mLogger.logUpdateCarrierTextForReason(REASON_ON_SIM_STATE_CHANGED); + + mLogger.logSimStateChangedCallback(subId, slotId, simState); if (getStatusForIccState(simState) == CarrierTextManager.StatusMode.SimIoError) { mSimErrorState[slotId] = true; + mLogger.logUpdateCarrierTextForReason(REASON_SIM_ERROR_STATE_CHANGED); updateCarrierText(); } else if (mSimErrorState[slotId]) { mSimErrorState[slotId] = false; + mLogger.logUpdateCarrierTextForReason(REASON_SIM_ERROR_STATE_CHANGED); updateCarrierText(); } } diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt index 8b2a0ec27011..169a4e0f3501 100644 --- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt +++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt @@ -377,7 +377,9 @@ constructor( if (mode == ZenMode.OFF) SysuiR.string::dnd_is_off.name else SysuiR.string::dnd_is_on.name ).also { data -> - clock?.run { events.onZenDataChanged(data) } + mainExecutor.execute { + clock?.run { events.onZenDataChanged(data) } + } } } @@ -411,7 +413,6 @@ constructor( listenForDozing(this) if (migrateClocksToBlueprint()) { listenForDozeAmountTransition(this) - listenForAnyStateToAodTransition(this) } else { listenForDozeAmount(this) } @@ -520,19 +521,6 @@ constructor( } } - /** - * When keyguard is displayed again after being gone, the clock must be reset to full dozing. - */ - @VisibleForTesting - internal fun listenForAnyStateToAodTransition(scope: CoroutineScope): Job { - return scope.launch { - keyguardTransitionInteractor.transitionStepsToState(AOD) - .filter { it.transitionState == TransitionState.STARTED } - .filter { it.from != LOCKSCREEN } - .collect { handleDoze(1f) } - } - } - @VisibleForTesting internal fun listenForDozing(scope: CoroutineScope): Job { return scope.launch { diff --git a/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt index d02b72f37795..cb474d3d7a92 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/CarrierTextManagerLogger.kt @@ -94,6 +94,20 @@ class CarrierTextManagerLogger @Inject constructor(@CarrierTextManagerLog val bu ) } + fun logSimStateChangedCallback(subId: Int, slotId: Int, simState: Int) { + buffer.log( + TAG, + LogLevel.VERBOSE, + { + // subId is always a very small int, and we've run out of integers for log buffer + long1 = subId.toLong() + int1 = slotId + int2 = simState + }, + { "onSimStateChangedCallback: subId=$long1 slotId=$int1 simState=$int2" } + ) + } + /** * Used to log the starting point for _why_ the carrier text is updating. In order to keep us * from holding on to too many objects, we'll just use simple ints for reasons here @@ -113,7 +127,7 @@ class CarrierTextManagerLogger @Inject constructor(@CarrierTextManagerLog val bu companion object { const val REASON_REFRESH_CARRIER_INFO = 1 const val REASON_ON_TELEPHONY_CAPABLE = 2 - const val REASON_ON_SIM_STATE_CHANGED = 3 + const val REASON_SIM_ERROR_STATE_CHANGED = 3 const val REASON_ACTIVE_DATA_SUB_CHANGED = 4 @Retention(AnnotationRetention.SOURCE) @@ -122,7 +136,7 @@ class CarrierTextManagerLogger @Inject constructor(@CarrierTextManagerLog val bu [ REASON_REFRESH_CARRIER_INFO, REASON_ON_TELEPHONY_CAPABLE, - REASON_ON_SIM_STATE_CHANGED, + REASON_SIM_ERROR_STATE_CHANGED, REASON_ACTIVE_DATA_SUB_CHANGED, ] ) @@ -132,7 +146,7 @@ class CarrierTextManagerLogger @Inject constructor(@CarrierTextManagerLog val bu when (this) { REASON_REFRESH_CARRIER_INFO -> "REFRESH_CARRIER_INFO" REASON_ON_TELEPHONY_CAPABLE -> "ON_TELEPHONY_CAPABLE" - REASON_ON_SIM_STATE_CHANGED -> "SIM_STATE_CHANGED" + REASON_SIM_ERROR_STATE_CHANGED -> "SIM_ERROR_STATE_CHANGED" REASON_ACTIVE_DATA_SUB_CHANGED -> "ACTIVE_DATA_SUB_CHANGED" else -> "unknown" } diff --git a/packages/SystemUI/src/com/android/systemui/DualToneHandler.kt b/packages/SystemUI/src/com/android/systemui/DualToneHandler.kt index 22d0bc9e4b5c..af810ea1bc2e 100644 --- a/packages/SystemUI/src/com/android/systemui/DualToneHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/DualToneHandler.kt @@ -20,6 +20,7 @@ import android.animation.ArgbEvaluator import android.content.Context import android.view.ContextThemeWrapper import com.android.settingslib.Utils +import com.android.settingslib.flags.Flags.newStatusBarIcons import com.android.systemui.res.R /** @@ -53,14 +54,26 @@ class DualToneHandler(context: Context) { Utils.getThemeAttr(context, R.attr.darkIconTheme)) val dualToneLightTheme = ContextThemeWrapper(context, Utils.getThemeAttr(context, R.attr.lightIconTheme)) - darkColor = Color( - Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.singleToneColor), + if (newStatusBarIcons()) { + darkColor = Color( + android.graphics.Color.BLACK, Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.iconBackgroundColor), Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.fillColor)) - lightColor = Color( - Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.singleToneColor), + + lightColor = Color( + android.graphics.Color.WHITE, Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.iconBackgroundColor), Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.fillColor)) + } else { + darkColor = Color( + Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.singleToneColor), + Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.iconBackgroundColor), + Utils.getColorAttrDefaultColor(dualToneDarkTheme, R.attr.fillColor)) + lightColor = Color( + Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.singleToneColor), + Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.iconBackgroundColor), + Utils.getColorAttrDefaultColor(dualToneLightTheme, R.attr.fillColor)) + } } private fun getColorForDarkIntensity(darkIntensity: Float, lightColor: Int, darkColor: Int) = diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java index d2fda4cfd186..88fa2de186d0 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java @@ -273,6 +273,10 @@ public class Magnification implements CoreStartable, CommandQueue.Callbacks { } } + void onFullscreenMagnificationActivationChanged(int displayId, boolean activated) { + // Do nothing + } + @MainThread void toggleSettingsPanelVisibility(int displayId) { final MagnificationSettingsController magnificationSettingsController = diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationConnectionImpl.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationConnectionImpl.java index ba943b07b704..b5f3aef88dc4 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationConnectionImpl.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationConnectionImpl.java @@ -47,6 +47,12 @@ class MagnificationConnectionImpl extends IMagnificationConnection.Stub { } @Override + public void onFullscreenMagnificationActivationChanged(int displayId, boolean activated) { + mHandler.post(() -> mMagnification + .onFullscreenMagnificationActivationChanged(displayId, activated)); + } + + @Override public void enableWindowMagnification(int displayId, float scale, float centerX, float centerY, float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY, IRemoteMagnificationAnimationCallback callback) { diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index 74ea58caf8b6..d30f33f5ba2c 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -31,6 +31,7 @@ import com.android.internal.app.IVisualQueryRecognitionStatusListener; import com.android.internal.app.IVoiceInteractionSessionListener; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.systemui.assist.domain.interactor.AssistInteractor; import com.android.systemui.assist.ui.DefaultUiController; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; @@ -149,6 +150,7 @@ public class AssistManager { private final SecureSettings mSecureSettings; private final SelectedUserInteractor mSelectedUserInteractor; private final ActivityManager mActivityManager; + private final AssistInteractor mInteractor; private final DeviceProvisionedController mDeviceProvisionedController; @@ -192,7 +194,8 @@ public class AssistManager { DisplayTracker displayTracker, SecureSettings secureSettings, SelectedUserInteractor selectedUserInteractor, - ActivityManager activityManager) { + ActivityManager activityManager, + AssistInteractor interactor) { mContext = context; mDeviceProvisionedController = controller; mCommandQueue = commandQueue; @@ -206,6 +209,7 @@ public class AssistManager { mSecureSettings = secureSettings; mSelectedUserInteractor = selectedUserInteractor; mActivityManager = activityManager; + mInteractor = interactor; registerVoiceInteractionSessionListener(); registerVisualQueryRecognitionStatusListener(); @@ -314,6 +318,7 @@ public class AssistManager { assistComponent, legacyDeviceState); logStartAssistLegacy(legacyInvocationType, legacyDeviceState); + mInteractor.onAssistantStarted(legacyInvocationType); startAssistInternal(args, assistComponent, isService); } diff --git a/packages/SystemUI/src/com/android/systemui/assist/data/repository/AssistRepository.kt b/packages/SystemUI/src/com/android/systemui/assist/data/repository/AssistRepository.kt new file mode 100644 index 000000000000..c416c249dec4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/assist/data/repository/AssistRepository.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.assist.data.repository + +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.asSharedFlow + +@SysUISingleton +class AssistRepository @Inject constructor() { + private val _latestInvocationType = + MutableSharedFlow<Int>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) + /** The type of the latest invocation of the assistant. */ + val latestInvocationType: SharedFlow<Int> = _latestInvocationType.asSharedFlow() + + /** Sets the type of the latest invocation of the assistant. */ + fun setLatestInvocationType(type: Int) { + _latestInvocationType.tryEmit(type) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/assist/domain/interactor/AssistInteractor.kt b/packages/SystemUI/src/com/android/systemui/assist/domain/interactor/AssistInteractor.kt new file mode 100644 index 000000000000..d9e46aabf539 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/assist/domain/interactor/AssistInteractor.kt @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.assist.domain.interactor + +import com.android.systemui.Flags +import com.android.systemui.assist.data.repository.AssistRepository +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject +import kotlinx.coroutines.flow.SharedFlow + +@SysUISingleton +class AssistInteractor +@Inject +constructor( + private val repository: AssistRepository, +) { + /** The type of the latest invocation of the assistant. */ + val latestInvocationType: SharedFlow<Int> = repository.latestInvocationType + + /** Notifies that Assistant has been started. */ + fun onAssistantStarted(type: Int) { + if (Flags.enableContextualTips() && Flags.enableContextualTipForPowerOff()) { + repository.setLatestInvocationType(type) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java index b1a153aa86aa..31698a35c811 100644 --- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java +++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java @@ -17,6 +17,7 @@ package com.android.systemui.battery; import static android.provider.Settings.System.SHOW_BATTERY_PERCENT; +import static com.android.settingslib.flags.Flags.newStatusBarIcons; import static com.android.systemui.DejankUtils.whitelistIpcs; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -25,6 +26,7 @@ import android.animation.LayoutTransition; import android.animation.ObjectAnimator; import android.annotation.IntDef; import android.annotation.IntRange; +import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -47,6 +49,9 @@ import androidx.annotation.VisibleForTesting; import com.android.app.animation.Interpolators; import com.android.systemui.DualToneHandler; +import com.android.systemui.battery.unified.BatteryColors; +import com.android.systemui.battery.unified.BatteryDrawableState; +import com.android.systemui.battery.unified.BatteryLayersDrawable; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.res.R; @@ -78,6 +83,7 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { private boolean mShowPercentAvailable; private String mEstimateText = null; private boolean mPluggedIn; + private boolean mPowerSaveEnabled; private boolean mIsBatteryDefender; private boolean mIsIncompatibleCharging; private boolean mDisplayShieldEnabled; @@ -91,6 +97,12 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { private BatteryEstimateFetcher mBatteryEstimateFetcher; + // for Flags.newStatusBarIcons. The unified battery icon can show percent inside + @Nullable private BatteryLayersDrawable mUnifiedBattery; + private BatteryColors mUnifiedBatteryColors = BatteryColors.LIGHT_THEME_COLORS; + private BatteryDrawableState mUnifiedBatteryState = + BatteryDrawableState.Companion.getDefaultInitialState(); + public BatteryMeterView(Context context, AttributeSet attrs) { this(context, attrs, 0); } @@ -106,6 +118,7 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor, context.getColor(com.android.settingslib.R.color.meter_background_color)); mPercentageStyleId = atts.getResourceId(R.styleable.BatteryMeterView_textAppearance, 0); + mDrawable = new AccessorizedBatteryDrawable(context, frameColor); atts.recycle(); @@ -115,13 +128,26 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { setupLayoutTransition(); mBatteryIconView = new ImageView(context); - mBatteryIconView.setImageDrawable(mDrawable); - final MarginLayoutParams mlp = new MarginLayoutParams( - getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_width), - getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_height)); - mlp.setMargins(0, 0, 0, - getResources().getDimensionPixelOffset(R.dimen.battery_margin_bottom)); - addView(mBatteryIconView, mlp); + if (newStatusBarIcons()) { + mUnifiedBattery = BatteryLayersDrawable.Companion + .newBatteryDrawable(context, mUnifiedBatteryState); + mBatteryIconView.setImageDrawable(mUnifiedBattery); + + final MarginLayoutParams mlp = new MarginLayoutParams( + getResources().getDimensionPixelSize( + R.dimen.status_bar_battery_unified_icon_width), + getResources().getDimensionPixelSize( + R.dimen.status_bar_battery_unified_icon_height)); + addView(mBatteryIconView, mlp); + } else { + mBatteryIconView.setImageDrawable(mDrawable); + final MarginLayoutParams mlp = new MarginLayoutParams( + getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_width), + getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_height)); + mlp.setMargins(0, 0, 0, + getResources().getDimensionPixelOffset(R.dimen.battery_margin_bottom)); + addView(mBatteryIconView, mlp); + } updateShowPercent(); mDualToneHandler = new DualToneHandler(context); @@ -132,6 +158,14 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { setClipToPadding(false); } + + private void setBatteryDrawableState(BatteryDrawableState newState) { + if (!newStatusBarIcons()) return; + + mUnifiedBatteryState = newState; + mUnifiedBattery.setBatteryState(mUnifiedBatteryState); + } + private void setupLayoutTransition() { LayoutTransition transition = new LayoutTransition(); transition.setDuration(200); @@ -200,25 +234,94 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { * @param pluggedIn whether the device is plugged in or not */ public void onBatteryLevelChanged(@IntRange(from = 0, to = 100) int level, boolean pluggedIn) { + boolean wasCharging = isCharging(); mPluggedIn = pluggedIn; mLevel = level; - mDrawable.setCharging(isCharging()); + boolean isCharging = isCharging(); + mDrawable.setCharging(isCharging); mDrawable.setBatteryLevel(level); updatePercentText(); + + if (newStatusBarIcons()) { + Drawable attr = mUnifiedBatteryState.getAttribution(); + if (isCharging != wasCharging) { + attr = getBatteryAttribution(isCharging); + } + + BatteryDrawableState newState = + new BatteryDrawableState( + level, + mUnifiedBatteryState.getShowPercent(), + level <= 20, + attr + ); + + setBatteryDrawableState(newState); + } + } + + // Potentially reloads any attribution. Should not be called if the state hasn't changed + private Drawable getBatteryAttribution(boolean isCharging) { + if (!newStatusBarIcons()) return null; + + int resId = 0; + if (mPowerSaveEnabled) { + resId = R.drawable.battery_unified_attr_powersave; + } else if (mIsBatteryDefender && mDisplayShieldEnabled) { + resId = R.drawable.battery_unified_attr_defend; + } else if (isCharging) { + resId = R.drawable.battery_unified_attr_charging; + } + + Drawable attr = null; + if (resId > 0) { + attr = mContext.getDrawable(resId); + } + + return attr; } void onPowerSaveChanged(boolean isPowerSave) { - mDrawable.setPowerSaveEnabled(isPowerSave); + if (isPowerSave == mPowerSaveEnabled) { + return; + } + mPowerSaveEnabled = isPowerSave; + if (!newStatusBarIcons()) { + mDrawable.setPowerSaveEnabled(isPowerSave); + } else { + setBatteryDrawableState( + new BatteryDrawableState( + mUnifiedBatteryState.getLevel(), + mUnifiedBatteryState.getShowPercent(), + mUnifiedBatteryState.getShowErrorState(), + getBatteryAttribution(isCharging()) + ) + ); + } } void onIsBatteryDefenderChanged(boolean isBatteryDefender) { boolean valueChanged = mIsBatteryDefender != isBatteryDefender; mIsBatteryDefender = isBatteryDefender; - if (valueChanged) { - updateContentDescription(); + + if (!valueChanged) { + return; + } + + updateContentDescription(); + if (!newStatusBarIcons()) { // The battery drawable is a different size depending on whether it's currently // overheated or not, so we need to re-scale the view when overheated changes. scaleBatteryMeterViews(); + } else { + setBatteryDrawableState( + new BatteryDrawableState( + mUnifiedBatteryState.getLevel(), + mUnifiedBatteryState.getShowPercent(), + mUnifiedBatteryState.getShowErrorState(), + getBatteryAttribution(isCharging()) + ) + ); } } @@ -226,7 +329,18 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { boolean valueChanged = mIsIncompatibleCharging != isIncompatibleCharging; mIsIncompatibleCharging = isIncompatibleCharging; if (valueChanged) { - mDrawable.setCharging(isCharging()); + if (newStatusBarIcons()) { + setBatteryDrawableState( + new BatteryDrawableState( + mUnifiedBatteryState.getLevel(), + mUnifiedBatteryState.getShowPercent(), + mUnifiedBatteryState.getShowErrorState(), + getBatteryAttribution(isCharging()) + ) + ); + } else { + mDrawable.setCharging(isCharging()); + } updateContentDescription(); } } @@ -260,6 +374,38 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { } void updatePercentText() { + if (!newStatusBarIcons()) { + updatePercentTextLegacy(); + return; + } + + // The unified battery can show the percent inside, so we only need to handle + // the estimated time remaining case + if (mShowPercentMode == MODE_ESTIMATE + && mBatteryEstimateFetcher != null + && !isCharging() + ) { + mBatteryEstimateFetcher.fetchBatteryTimeRemainingEstimate( + (String estimate) -> { + if (mBatteryPercentView == null) { + mBatteryPercentView = loadPercentView(); + } + if (estimate != null && mShowPercentMode == MODE_ESTIMATE) { + mEstimateText = estimate; + mBatteryPercentView.setText(estimate); + updateContentDescription(); + } else { + mEstimateText = null; + mBatteryPercentView.setText(null); + updateContentDescription(); + } + }); + } else { + updateContentDescription(); + } + } + + void updatePercentTextLegacy() { if (mBatteryStateUnknown) { return; } @@ -334,6 +480,45 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { } void updateShowPercent() { + if (!newStatusBarIcons()) { + updateShowPercentLegacy(); + return; + } + + if (mUnifiedBattery == null) { + return; + } + + // TODO(b/140051051) + final boolean systemSetting = 0 != whitelistIpcs(() -> Settings.System + .getIntForUser(getContext().getContentResolver(), + SHOW_BATTERY_PERCENT, getContext().getResources().getBoolean( + com.android.internal.R.bool.config_defaultBatteryPercentageSetting) + ? 1 : 0, UserHandle.USER_CURRENT)); + + boolean shouldShow = + (mShowPercentAvailable && systemSetting && mShowPercentMode != MODE_OFF) + || mShowPercentMode == MODE_ON; + shouldShow = shouldShow && !mBatteryStateUnknown; + + setBatteryDrawableState( + new BatteryDrawableState( + mUnifiedBatteryState.getLevel(), + shouldShow, + mUnifiedBatteryState.getShowErrorState(), + mUnifiedBatteryState.getAttribution() + ) + ); + + // The legacy impl used the percent view for the estimate and the percent text. The modern + // version only uses it for estimate. It can be safely removed here + if (mShowPercentMode != MODE_ESTIMATE) { + removeView(mBatteryPercentView); + mBatteryPercentView = null; + } + } + + private void updateShowPercentLegacy() { final boolean showing = mBatteryPercentView != null; // TODO(b/140051051) final boolean systemSetting = 0 != whitelistIpcs(() -> Settings.System @@ -395,10 +580,39 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { updateShowPercent(); } + void scaleBatteryMeterViews() { + if (!newStatusBarIcons()) { + scaleBatteryMeterViewsLegacy(); + return; + } + + // For simplicity's sake, copy the general pattern in the legacy method and use the new + // resources, excluding what we don't need + Resources res = getContext().getResources(); + TypedValue typedValue = new TypedValue(); + + res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true); + float iconScaleFactor = typedValue.getFloat(); + + float mainBatteryHeight = + res.getDimensionPixelSize( + R.dimen.status_bar_battery_unified_icon_height) * iconScaleFactor; + float mainBatteryWidth = + res.getDimensionPixelSize( + R.dimen.status_bar_battery_unified_icon_width) * iconScaleFactor; + + LinearLayout.LayoutParams scaledLayoutParams = new LinearLayout.LayoutParams( + Math.round(mainBatteryWidth), + Math.round(mainBatteryHeight)); + + mBatteryIconView.setLayoutParams(scaledLayoutParams); + mBatteryIconView.invalidateDrawable(mUnifiedBattery); + } + /** * Looks up the scale factor for status bar icons and scales the battery view by that amount. */ - void scaleBatteryMeterViews() { + void scaleBatteryMeterViewsLegacy() { Resources res = getContext().getResources(); TypedValue typedValue = new TypedValue(); @@ -445,6 +659,32 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { @Override public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) { if (mIsStaticColor) return; + + if (!newStatusBarIcons()) { + onDarkChangedLegacy(areas, darkIntensity, tint); + return; + } + + if (mUnifiedBattery == null) { + return; + } + + if (DarkIconDispatcher.isInAreas(areas, this)) { + if (darkIntensity < 0.5) { + mUnifiedBatteryColors = BatteryColors.DARK_THEME_COLORS; + } else { + mUnifiedBatteryColors = BatteryColors.LIGHT_THEME_COLORS; + } + + mUnifiedBattery.setColors(mUnifiedBatteryColors); + } else { + // Same behavior as the legacy code when not isInArea + mUnifiedBatteryColors = BatteryColors.DARK_THEME_COLORS; + mUnifiedBattery.setColors(mUnifiedBatteryColors); + } + } + + private void onDarkChangedLegacy(ArrayList<Rect> areas, float darkIntensity, int tint) { float intensity = DarkIconDispatcher.isInAreas(areas, this) ? darkIntensity : 0; int nonAdaptedSingleToneColor = mDualToneHandler.getSingleColor(intensity); int nonAdaptedForegroundColor = mDualToneHandler.getFillColor(intensity); @@ -478,7 +718,16 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { } } - private boolean isCharging() { + /** For newStatusBarIcons(), we use a BatteryColors object to declare the theme */ + public void setUnifiedBatteryColors(BatteryColors colors) { + if (!newStatusBarIcons()) return; + + mUnifiedBatteryColors = colors; + mUnifiedBattery.setColors(mUnifiedBatteryColors); + } + + @VisibleForTesting + boolean isCharging() { return mPluggedIn && !mIsIncompatibleCharging; } @@ -505,6 +754,16 @@ public class BatteryMeterView extends LinearLayout implements DarkReceiver { return mBatteryPercentView.getText(); } + @VisibleForTesting + TextView getBatteryPercentView() { + return mBatteryPercentView; + } + + @VisibleForTesting + BatteryDrawableState getUnifiedBatteryState() { + return mUnifiedBatteryState; + } + /** An interface that will fetch the estimated time remaining for the user's battery. */ public interface BatteryEstimateFetcher { void fetchBatteryTimeRemainingEstimate( diff --git a/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryAttributionDrawable.kt b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryAttributionDrawable.kt new file mode 100644 index 000000000000..1b8495ace243 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryAttributionDrawable.kt @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.battery.unified + +import android.graphics.Canvas +import android.graphics.ColorFilter +import android.graphics.PixelFormat +import android.graphics.Rect +import android.graphics.drawable.Drawable +import android.graphics.drawable.DrawableWrapper +import android.view.Gravity +import kotlin.math.min +import kotlin.math.roundToInt + +/** + * A battery attribution is defined as a drawable that can display either alongside the percent text + * or solely in the center of the battery frame. + * + * Attributions are given an explicit canvas of 18x8, or 6x6 depending on the display mode (centered + * or right-aligned). The size is configured in [BatteryLayersDrawable] by changing this drawable + * wrapper's bounds, and optionally setting the [gravity] + */ +@Suppress("RtlHardcoded") +class BatteryAttributionDrawable(dr: Drawable?) : DrawableWrapper(dr) { + /** One of [CENTER, LEFT]. Note that RTL is handled in the parent */ + var gravity = Gravity.CENTER + set(value) { + field = value + updateBoundsInner() + } + + // Must be called if bounds change, gravity changes, or the wrapped drawable changes + private fun updateBoundsInner() { + val dr = drawable ?: return + + val hScale = bounds.width().toFloat() / dr.intrinsicWidth.toFloat() + val vScale = bounds.height().toFloat() / dr.intrinsicHeight.toFloat() + val scale = min(hScale, vScale) + + val dw = scale * dr.intrinsicWidth + val dh = scale * dr.intrinsicHeight + + if (gravity == Gravity.CENTER) { + val padLeft = (bounds.width() - dw) / 2 + val padTop = (bounds.height() - dh) / 2 + dr.setBounds( + (bounds.left + padLeft).roundToInt(), + (bounds.top + padTop).roundToInt(), + (bounds.left + padLeft + dw).roundToInt(), + (bounds.top + padTop + dh).roundToInt() + ) + } else if (gravity == Gravity.LEFT) { + dr.setBounds( + bounds.left, + bounds.top, + (bounds.left + dw).roundToInt(), + (bounds.top + dh).roundToInt() + ) + } + } + + override fun setDrawable(dr: Drawable?) { + super.setDrawable(dr) + updateBoundsInner() + } + + override fun onBoundsChange(bounds: Rect) { + updateBoundsInner() + } + + /** + * DrawableWrapper allows for a null constructor, but this method assumes that the drawable is + * non-null. It is called by LayerDrawable on init, so we have to handle null here specifically + */ + override fun getChangingConfigurations(): Int = drawable?.changingConfigurations ?: 0 + + override fun draw(canvas: Canvas) { + drawable?.draw(canvas) + } + + // Deprecated, but needed for Drawable implementation + override fun getOpacity() = PixelFormat.OPAQUE + + // We don't use this + override fun setAlpha(alpha: Int) {} + + override fun setColorFilter(colorFilter: ColorFilter?) {} +} diff --git a/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryDrawableState.kt b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryDrawableState.kt new file mode 100644 index 000000000000..b5a93b6635c6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryDrawableState.kt @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.battery.unified + +import android.graphics.Color +import android.graphics.drawable.Drawable + +/** + * Encapsulates all drawing information needed by BatteryMeterDrawable to render properly. Rendered + * state will be equivalent to the most recent state passed in. + */ +data class BatteryDrawableState( + /** [0-100] description of the battery level */ + val level: Int, + /** Whether or not to render the percent as a foreground text layer */ + val showPercent: Boolean, + /** + * In an error state, the drawable will use the error colors and removes the third layer. If + * [showPercent] is false, then the fill will be rendered in the foreground error color. Else + * the fill is not rendered. + */ + val showErrorState: Boolean, + + /** + * An attribution is a drawable that shows either alongside the percent, or centered in the + * foreground of the overall drawable. + * + * When space sharing with the percent text, the default rect is 6x6, positioned directly next + * to the percent and left-aligned. + * + * When the attribution is the only foreground layer, then we use a 16x8 canvas and center this + * drawable. + * + * In both cases, we use a FIT_CENTER style scaling. Note that for now the attributions will + * have to configure their own padding inside of their vector definitions. Future versions + * should abstract the side- and center- canvases and allow attributions to be defined with + * separate designs for each case. + */ + val attribution: Drawable? +) { + fun hasForegroundContent() = showPercent || attribution != null + + companion object { + val DefaultInitialState = + BatteryDrawableState( + level = 50, + showPercent = false, + showErrorState = false, + attribution = null, + ) + } +} + +sealed interface BatteryColors { + /** The color for the frame and any foreground attributions for the battery */ + val fg: Int + /** + * Default color for the frame background. Configured to be a transparent white or black that + * matches the current mode (white for light theme, black for dark theme) and provides extra + * contrast for the drawable + */ + val bg: Int + + /** Color for the level fill when there is an attribution on top */ + val fill: Int + /** + * When there is no attribution, [fillOnlyColor] describes an opaque color with more contrast + */ + val fillOnly: Int + + /** Error colors are used for low battery states typically */ + val errorForeground: Int + val errorBackground: Int + + /** Currently unused */ + val warnBackground: Int + + /** Color scheme appropriate for light mode (dark icons) */ + data object LightThemeColors : BatteryColors { + override val fg = Color.BLACK + // 22% alpha white + override val bg: Int = Color.valueOf(1f, 1f, 1f, 0.22f).toArgb() + + // 18% alpha black + override val fill = Color.valueOf(0f, 0f, 0f, 0.18f).toArgb() + // GM Gray 500 + override val fillOnly = Color.parseColor("#9AA0A6") + + // GM Red 600 + override val errorForeground = Color.parseColor("#D93025") + // GM Red 100 + override val errorBackground = Color.parseColor("#FAD2CF") + + // GM Yellow 500 + override val warnBackground = Color.parseColor("#FBBC04") + } + + /** Color scheme appropriate for dark mode (light icons) */ + data object DarkThemeColors : BatteryColors { + override val fg = Color.WHITE + // 18% alpha black + override val bg: Int = Color.valueOf(0f, 0f, 0f, 0.18f).toArgb() + + // 22% alpha white + override val fill = Color.valueOf(1f, 1f, 1f, 0.22f).toArgb() + // GM Gray 600 + override val fillOnly = Color.parseColor("#80868B") + + // GM Red 600 + override val errorForeground = Color.parseColor("#D93025") + // GM Red 200 + override val errorBackground = Color.parseColor("#F6AEA9") + // GM Yellow + override val warnBackground = Color.parseColor("#FBBC04") + } + + companion object { + /** For use from java */ + @JvmField val LIGHT_THEME_COLORS = LightThemeColors + + @JvmField val DARK_THEME_COLORS = DarkThemeColors + } +} diff --git a/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryFillDrawable.kt b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryFillDrawable.kt new file mode 100644 index 000000000000..6d3206767d2b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryFillDrawable.kt @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.battery.unified + +import android.graphics.BlendMode +import android.graphics.Canvas +import android.graphics.ColorFilter +import android.graphics.Matrix +import android.graphics.Paint +import android.graphics.Path +import android.graphics.PixelFormat +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.drawable.Drawable +import com.android.systemui.battery.unified.BatteryLayersDrawable.Companion.Metrics +import kotlin.math.floor +import kotlin.math.roundToInt + +/** + * Draws a right-to-left fill inside of the given [framePath]. This fill is designed to exactly fill + * the usable space inside of [framePath], given that the stroke width of the path is 1.5, and we + * want an extra 0.25 (canvas units) of a gap between the fill and the stroke + */ +class BatteryFillDrawable(private val framePath: Path) : Drawable() { + private var hScale = 1f + private val scaleMatrix = Matrix().also { it.setScale(1f, 1f) } + private val scaledPath = Path() + private val scaledFillRect = RectF() + private var scaledLeftOffset = 0f + private var scaledRightInset = 0f + + // Drawable.level cannot be overloaded + var batteryLevel = 0 + set(value) { + field = value + invalidateSelf() + } + + var fillColor: Int = 0 + set(value) { + field = value + fillPaint.color = value + invalidateSelf() + } + + private val clearPaint = + Paint(Paint.ANTI_ALIAS_FLAG).also { p -> + p.style = Paint.Style.STROKE + p.strokeWidth = 5f + p.blendMode = BlendMode.CLEAR + } + + private val fillPaint = + Paint(Paint.ANTI_ALIAS_FLAG).also { p -> + p.style = Paint.Style.FILL + p.color = fillColor + } + + override fun onBoundsChange(bounds: Rect) { + super.onBoundsChange(bounds) + + hScale = bounds.right / Metrics.ViewportWidth + + if (bounds.isEmpty) { + scaleMatrix.setScale(1f, 1f) + } else { + scaleMatrix.setScale( + (bounds.right / Metrics.ViewportWidth), + (bounds.bottom / Metrics.ViewportHeight) + ) + } + + updateScale() + } + + private fun updateScale() { + framePath.transform(/* matrix = */ scaleMatrix, /* dst = */ scaledPath) + scaleMatrix.mapRect(/* dst = */ scaledFillRect, /* src = */ FillRect) + + scaledLeftOffset = LeftFillOffset * hScale + scaledRightInset = RightFillInset * hScale + } + + override fun draw(canvas: Canvas) { + if (batteryLevel == 0) { + return + } + + // saveLayer is needed here so we don't clip the other layers of our drawable + canvas.saveLayer(null, null) + + // We need to use 3 draw commands: + // 1. Clip to the current level + // 2. Clip anything outside of the path + // 3. render the fill as a rect the correct size to fit the inner space + // 4. Clip out the padding between the frame and the fill + + val fillLeft: Int = + if (batteryLevel == 100) { + 0 + } else { + val fillFraction = batteryLevel / 100f + floor(scaledFillRect.width() * (1 - fillFraction)).roundToInt() + } + + // Clip to the fill level + canvas.clipOutRect( + scaledLeftOffset, + bounds.top.toFloat(), + scaledLeftOffset + fillLeft, + bounds.height().toFloat() + ) + // Clip everything outside of the path + canvas.clipPath(scaledPath) + + // Draw the fill + canvas.drawRect(scaledFillRect, fillPaint) + + // Clear around the fill + canvas.drawPath(scaledPath, clearPaint) + + // Finally, restore the layer + canvas.restore() + } + + override fun setColorFilter(colorFilter: ColorFilter?) { + clearPaint.setColorFilter(colorFilter) + fillPaint.setColorFilter(colorFilter) + } + + // unused + override fun getOpacity(): Int = PixelFormat.OPAQUE + + // unused + override fun setAlpha(alpha: Int) {} + + companion object { + // 3.75f = + // 2.75 (left-most edge of the frame path) + // + 0.75 (1/2 of the stroke width) + // + 0.25 (padding between stroke and fill edge) + private const val LeftFillOffset = 3.75f + + // 1.75, calculated the same way, but from the right edge (without the battery cap), which + // consumes 2 units of width. + private const val RightFillInset = 1.75f + + /** Scale this to the viewport so we fill correctly! */ + private val FillRect = + RectF( + LeftFillOffset, + 0f, + Metrics.ViewportWidth - RightFillInset, + Metrics.ViewportHeight + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryLayersDrawable.kt b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryLayersDrawable.kt new file mode 100644 index 000000000000..199dd1f18a42 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryLayersDrawable.kt @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.battery.unified + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Matrix +import android.graphics.Rect +import android.graphics.RectF +import android.graphics.Typeface +import android.graphics.drawable.Drawable +import android.graphics.drawable.LayerDrawable +import android.util.PathParser +import android.view.Gravity +import com.android.systemui.res.R +import kotlin.math.roundToInt + +/** + * Custom [Drawable] that manages a list of other drawables which, together, achieve an appropriate + * view for [BatteryDrawableState]. + * + * The main elements managed by this drawable are: + * + * 1. A battery frame background, which may show a solid fill color + * 2. The battery frame itself + * 3. A custom [BatteryFillDrawable], which renders a fill level, appropriately scale and + * clipped to the battery percent + * 4. Percent text + * 5. An attribution + * + * Layers (1) and (2) are loaded directly from xml, as they are static assets. Layer (3) contains a + * custom [Drawable.draw] implementation and uses the same path as the battery shape to achieve an + * appropriate fill shape. + * + * The text and attribution layers have the following behaviors: + * + * - When text-only or attribute-only, the foreground layer is centered and the maximum size + * - When sharing space between the attribute and the text: + * - The internal space is divided into 12x10 and 6x6 rectangles + * - The attribution is aligned left + * - The percent text is scaled based on the number of characters (1,2, or 3) in the string + * + * When [BatteryDrawableState.showErrorState] is true, we will only show either the percent text OR + * the battery fill, in order to maximize contrast when using the error colors. + */ +@Suppress("RtlHardcoded") +class BatteryLayersDrawable( + private val frameBg: Drawable, + private val frame: Drawable, + private val fill: BatteryFillDrawable, + private val textOnly: BatteryPercentTextOnlyDrawable, + private val spaceSharingText: BatterySpaceSharingPercentTextDrawable, + private val attribution: BatteryAttributionDrawable, + batteryState: BatteryDrawableState, +) : LayerDrawable(arrayOf(frameBg, frame, fill, textOnly, spaceSharingText, attribution)) { + + private val scaleMatrix = Matrix().also { it.setScale(1f, 1f) } + private val scaledAttrFullCanvas = RectF(Metrics.AttrFullCanvas) + private val scaledAttrRightCanvas = RectF(Metrics.AttrRightCanvas) + + var batteryState = batteryState + set(value) { + if (field != value) { + // Update before we set the backing field so we can diff + handleUpdateState(field, value) + field = value + invalidateSelf() + } + } + + var colors: BatteryColors = BatteryColors.LightThemeColors + set(value) { + field = value + updateColors(batteryState.showErrorState, value) + } + + private fun handleUpdateState(old: BatteryDrawableState, new: BatteryDrawableState) { + if (new.showErrorState != old.showErrorState) { + updateColors(new.showErrorState, colors) + } + + if (new.level != old.level) { + fill.batteryLevel = new.level + textOnly.batteryLevel = new.level + spaceSharingText.batteryLevel = new.level + } + + if (new.attribution != null && new.attribution != attribution.drawable) { + attribution.drawable = new.attribution + updateColors(new.showErrorState, colors) + } + + if (new.hasForegroundContent() != old.hasForegroundContent()) { + setFillColor(new.hasForegroundContent(), new.showErrorState, colors) + } + } + + /** In error states, we don't draw fill unless there is no foreground content (e.g., percent) */ + private fun updateColors(showErrorState: Boolean, colorInfo: BatteryColors) { + frameBg.setTint(if (showErrorState) colorInfo.errorBackground else colorInfo.bg) + frame.setTint(colorInfo.fg) + attribution.setTint(if (showErrorState) colorInfo.errorForeground else colorInfo.fg) + textOnly.setTint(if (showErrorState) colorInfo.errorForeground else colorInfo.fg) + spaceSharingText.setTint(if (showErrorState) colorInfo.errorForeground else colorInfo.fg) + setFillColor(batteryState.hasForegroundContent(), showErrorState, colorInfo) + } + + /** + * If there is a foreground layer, then we draw the fill with the low opacity + * [BatteryColors.fill] color. Otherwise, if there is no other foreground layer, we will use + * either the error or fillOnly colors for more contrast + */ + private fun setFillColor( + hasFg: Boolean, + error: Boolean, + colorInfo: BatteryColors, + ) { + if (hasFg) { + fill.fillColor = colorInfo.fill + } else { + fill.fillColor = if (error) colorInfo.errorForeground else colorInfo.fillOnly + } + } + + override fun onBoundsChange(bounds: Rect) { + super.onBoundsChange(bounds) + + scaleMatrix.setScale( + bounds.width() / Metrics.ViewportWidth, + bounds.height() / Metrics.ViewportHeight + ) + + // Scale the attribution bounds + scaleMatrix.mapRect(scaledAttrFullCanvas, Metrics.AttrFullCanvas) + scaleMatrix.mapRect(scaledAttrRightCanvas, Metrics.AttrRightCanvas) + } + + override fun draw(canvas: Canvas) { + // 1. Draw the frame bg + frameBg.draw(canvas) + // 2. Then the frame itself + frame.draw(canvas) + + // 3. Fill it the appropriate amount if non-error state or error + no attribute + if (!batteryState.showErrorState || !batteryState.hasForegroundContent()) { + fill.draw(canvas) + } + // 4. Decide what goes inside + if (batteryState.showPercent && batteryState.attribution != null) { + // 4a. percent & attribution. Implies space-sharing + + // Configure the attribute to draw in a smaller bounding box and align left + attribution.gravity = Gravity.LEFT + attribution.setBounds( + scaledAttrRightCanvas.left.roundToInt(), + scaledAttrRightCanvas.top.roundToInt(), + scaledAttrRightCanvas.right.roundToInt(), + scaledAttrRightCanvas.bottom.roundToInt(), + ) + attribution.draw(canvas) + + spaceSharingText.draw(canvas) + } else if (batteryState.showPercent) { + // 4b. Percent only + textOnly.draw(canvas) + } else if (batteryState.attribution != null) { + // 4c. Attribution only + attribution.gravity = Gravity.CENTER + attribution.setBounds( + scaledAttrFullCanvas.left.roundToInt(), + scaledAttrFullCanvas.top.roundToInt(), + scaledAttrFullCanvas.right.roundToInt(), + scaledAttrFullCanvas.bottom.roundToInt(), + ) + attribution.draw(canvas) + } + } + + /** + * This drawable relies on [BatteryColors] to encode all alpha in their values, so we ignore + * externally-set alpha + */ + override fun setAlpha(alpha: Int) {} + + interface M { + val ViewportWidth: Float + val ViewportHeight: Float + + // Bounds, oriented in the above viewport, where we will fit-center and center-align + // an attribution that is the sole foreground element + val AttrFullCanvas: RectF + // Bounds, oriented in the above viewport, where we will fit-center and left-align + // an attribution that is sharing space with the percent text of the drawable + val AttrRightCanvas: RectF + } + + companion object { + private val PercentFont = Typeface.create("google-sans", Typeface.BOLD) + + /** + * Think of this like the `android:<attr>` values in a drawable.xml file. [Metrics] defines + * relevant canvas and size information for us to layout this cluster of drawables + */ + val Metrics = + object : M { + override val ViewportWidth: Float = 24f + override val ViewportHeight: Float = 14f + + /** + * Bounds, oriented in the above viewport, where we will fit-center and center-align + * an attribution that is the sole foreground element + * + * 18x8 point size + */ + override val AttrFullCanvas: RectF = RectF(4f, 3f, 22f, 11f) + /** + * Bounds, oriented in the above viewport, where we will fit-center and left-align + * an attribution that is sharing space with the percent text of the drawable + * + * 6x6 point size + */ + override val AttrRightCanvas: RectF = RectF(16f, 4f, 22f, 10f) + } + + /** + * Create all of the layers needed by [BatteryLayersDrawable]. This class relies on the + * following resources to exist in order to properly render: + * - R.drawable.battery_unified_frame_bg + * - R.drawable.battery_unified_frame + * - R.string.battery_unified_frame_path_string + * - GoogleSans bold font + * + * See [BatteryDrawableState] for how to set the properties of the resulting class + */ + fun newBatteryDrawable( + context: Context, + initialState: BatteryDrawableState = BatteryDrawableState.DefaultInitialState, + ): BatteryLayersDrawable { + val framePath = + PathParser.createPathFromPathData( + context.getString(R.string.battery_unified_frame_path_string) + ) + + val frameBg = + context.getDrawable(R.drawable.battery_unified_frame_bg) + ?: throw IllegalStateException("Missing battery_unified_frame_bg.xml") + val frame = + context.getDrawable(R.drawable.battery_unified_frame) + ?: throw IllegalStateException("Missing battery_unified_frame.xml") + val fill = BatteryFillDrawable(framePath) + val textOnly = BatteryPercentTextOnlyDrawable(PercentFont) + val spaceSharingText = BatterySpaceSharingPercentTextDrawable(PercentFont) + val attribution = BatteryAttributionDrawable(null) + + return BatteryLayersDrawable( + frameBg = frameBg, + frame = frame, + fill = fill, + textOnly = textOnly, + spaceSharingText = spaceSharingText, + attribution = attribution, + batteryState = initialState, + ) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryPercentTextOnlyDrawable.kt b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryPercentTextOnlyDrawable.kt new file mode 100644 index 000000000000..123d6ba57900 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/battery/unified/BatteryPercentTextOnlyDrawable.kt @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.battery.unified + +import android.graphics.Canvas +import android.graphics.ColorFilter +import android.graphics.Paint +import android.graphics.PixelFormat +import android.graphics.Rect +import android.graphics.Typeface +import android.graphics.drawable.Drawable +import com.android.systemui.battery.unified.BatteryLayersDrawable.Companion.Metrics + +/** + * (Names are hard) this drawable calculates the percent text for inside of the + * [BatteryLayersDrawable], assuming that there is no other attribution in the foreground. In this + * case, we can use the maximum font size and center the text in the full render area inside of the + * frame. After accounting for the stroke width and the insets from there, our rendering area is + * 18x10 points. + * + * See [BatterySpaceSharingPercentTextDrawable] (names are still hard) for the space-sharing + * approach. + * + * Note that these drawing metrics are only tested to work with google-sans BOLD + */ +class BatteryPercentTextOnlyDrawable(font: Typeface) : Drawable() { + private var hScale = 1f + private var vScale = 1f + + // range 0-100 + var batteryLevel: Int = 100 + set(value) { + field = value + percentText = "$value" + invalidateSelf() + } + + private var percentText = "$batteryLevel" + + private val textPaint = + Paint().also { p -> + p.textSize = 10f + p.typeface = font + } + + override fun onBoundsChange(bounds: Rect) { + super.onBoundsChange(bounds) + + vScale = bounds.bottom / Metrics.ViewportHeight + hScale = bounds.right / Metrics.ViewportWidth + + updateScale() + } + + private fun updateScale() { + textPaint.textSize = TextSize * vScale + } + + override fun draw(canvas: Canvas) { + val totalAvailableHeight = CanvasHeight * vScale + + // Distribute the vertical whitespace around the text. This is a simplified version of + // the equation ((C - T) / 2) + T - V, where C == canvas height, T == text height, and V + // is the vertical nudge. + val offsetY = (totalAvailableHeight + textPaint.textSize) / 2 - (VerticalNudge * vScale) + + val totalAvailableWidth = CanvasWidth * hScale + val textWidth = textPaint.measureText(percentText) + val offsetX = (totalAvailableWidth - textWidth) / 2 + + // Draw the text centered in the available area + canvas.drawText( + percentText, + (ViewportInsetLeft * hScale) + offsetX, + (ViewportInsetTop * vScale) + offsetY, + textPaint + ) + } + + override fun setTint(tintColor: Int) { + textPaint.color = tintColor + super.setTint(tintColor) + } + + override fun getOpacity() = PixelFormat.OPAQUE + + override fun setAlpha(alpha: Int) {} + + override fun setColorFilter(colorFilter: ColorFilter?) {} + + companion object { + // Based on the 24x14 canvas, we can render in an 18x10 canvas, inset like so: + const val ViewportInsetLeft = 4f + const val ViewportInsetRight = 2f + const val ViewportInsetTop = 2f + const val CanvasHeight = 10f + const val CanvasWidth = 18f + + // raise the text up by a smidgen so that it is more centered. Experimentally determined + const val VerticalNudge = 1.5f + + // Experimentally-determined value + const val TextSize = 10f + } +} diff --git a/packages/SystemUI/src/com/android/systemui/battery/unified/BatterySpaceSharingPercentTextDrawable.kt b/packages/SystemUI/src/com/android/systemui/battery/unified/BatterySpaceSharingPercentTextDrawable.kt new file mode 100644 index 000000000000..0c418b9caa7d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/battery/unified/BatterySpaceSharingPercentTextDrawable.kt @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.battery.unified + +import android.graphics.Canvas +import android.graphics.ColorFilter +import android.graphics.Paint +import android.graphics.PixelFormat +import android.graphics.Rect +import android.graphics.Typeface +import android.graphics.drawable.Drawable +import com.android.systemui.battery.unified.BatteryLayersDrawable.Companion.Metrics + +/** + * A variant of [BatteryPercentTextOnlyDrawable] with the following differences: + * 1. It is defined on a canvas of 12x10 (shortened by 6 points horizontally) + * 2. Because of this, we scale the font according to the number of characters + * + * Note that these drawing metrics are only tested to work with google-sans BOLD + */ +class BatterySpaceSharingPercentTextDrawable(font: Typeface) : Drawable() { + private var verticalNudge = 0f + private var hScale = 1f + private var vScale = 1f + + // range 0-100 + var batteryLevel: Int = 88 + set(value) { + field = value + percentText = "$value" + invalidateSelf() + } + + private var percentText = "$batteryLevel" + set(value) { + field = value + numberOfCharacters = percentText.length + } + + private var numberOfCharacters = percentText.length + set(value) { + if (field != value) { + field = value + updateFontSize() + } + } + + private val textPaint = + Paint().also { p -> + p.textSize = 10f + p.typeface = font + } + + private fun updateFontSize() { + // These values are determined experimentally + when (numberOfCharacters) { + 3 -> { + verticalNudge = 1f + textPaint.textSize = 6f * hScale + } + // 1, 2 + else -> { + verticalNudge = 1.25f + textPaint.textSize = 9f * hScale + } + } + } + + private fun updateScale() { + updateFontSize() + } + + override fun onBoundsChange(bounds: Rect) { + super.onBoundsChange(bounds) + + hScale = bounds.right / Metrics.ViewportWidth + vScale = bounds.bottom / Metrics.ViewportHeight + + updateScale() + } + + override fun draw(canvas: Canvas) { + val totalAvailableHeight = CanvasHeight * vScale + + // Distribute the vertical whitespace around the text. This is a simplified version of + // the equation ((C - T) / 2) + T - V, where C == canvas height, T == text height, and V + // is the vertical nudge. + val offsetY = (totalAvailableHeight + textPaint.textSize) / 2 - (verticalNudge * vScale) + + val totalAvailableWidth = CanvasWidth * hScale + val textWidth = textPaint.measureText(percentText) + val offsetX = (totalAvailableWidth - textWidth) / 2 + + canvas.drawText( + percentText, + (ViewportInsetLeft * hScale) + offsetX, + (ViewportInsetTop * vScale) + offsetY, + textPaint + ) + } + + override fun setTint(tintColor: Int) { + textPaint.color = tintColor + super.setTint(tintColor) + } + + override fun getOpacity() = PixelFormat.OPAQUE + + override fun setAlpha(p0: Int) {} + + override fun setColorFilter(colorFilter: ColorFilter?) { + textPaint.colorFilter = colorFilter + } + + companion object { + private const val ViewportInsetLeft = 4f + private const val ViewportInsetTop = 2f + + private const val CanvasWidth = 12f + private const val CanvasHeight = 10f + } +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt index 921e39532f58..16865ca809d9 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt @@ -31,6 +31,7 @@ import android.hardware.biometrics.BiometricRequestConstants.RequestReason import android.hardware.fingerprint.IUdfpsOverlayControllerCallback import android.os.Build import android.os.RemoteException +import android.os.Trace import android.provider.Settings import android.util.Log import android.util.RotationUtils @@ -58,9 +59,9 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor import com.android.systemui.dump.DumpManager import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.power.domain.interactor.PowerInteractor -import com.android.systemui.power.shared.model.WakefulnessState import com.android.systemui.res.R import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.LockscreenShadeTransitionController @@ -125,11 +126,15 @@ class UdfpsControllerOverlay @JvmOverloads constructor( private val powerInteractor: PowerInteractor, @Application private val scope: CoroutineScope, ) { - private val isFinishedGoingToSleep: Flow<Unit> = - powerInteractor.detailedWakefulness - .filter { it.internalWakefulnessState == WakefulnessState.ASLEEP } + private val currentStateUpdatedToOffAodOrDozing: Flow<Unit> = + transitionInteractor.currentKeyguardState + .filter { + it == KeyguardState.OFF || + it == KeyguardState.AOD || + it == KeyguardState.DOZING + } .map { } // map to Unit - private var listenForAsleepJob: Job? = null + private var listenForCurrentKeyguardState: Job? = null private var addViewRunnable: Runnable? = null private var overlayViewLegacy: UdfpsView? = null private set @@ -280,18 +285,19 @@ class UdfpsControllerOverlay @JvmOverloads constructor( private fun addViewNowOrLater(view: View, animation: UdfpsAnimationViewController<*>?) { if (udfpsViewPerformance()) { addViewRunnable = kotlinx.coroutines.Runnable { + Trace.setCounter("UdfpsAddView", 1) windowManager.addView( view, coreLayoutParams.updateDimensions(animation) ) } - if (powerInteractor.detailedWakefulness.value.internalWakefulnessState - != WakefulnessState.STARTING_TO_SLEEP) { + if (powerInteractor.detailedWakefulness.value.isAwake()) { + // Device is awake, so we add the view immediately. addViewIfPending() } else { - listenForAsleepJob?.cancel() - listenForAsleepJob = scope.launch { - isFinishedGoingToSleep.collect { + listenForCurrentKeyguardState?.cancel() + listenForCurrentKeyguardState = scope.launch { + currentStateUpdatedToOffAodOrDozing.collect { addViewIfPending() } } @@ -306,7 +312,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor( private fun addViewIfPending() { addViewRunnable?.let { - listenForAsleepJob?.cancel() + listenForCurrentKeyguardState?.cancel() it.run() } addViewRunnable = null @@ -412,7 +418,14 @@ class UdfpsControllerOverlay @JvmOverloads constructor( udfpsDisplayModeProvider.disable(null) } getTouchOverlay()?.apply { - windowManager.removeView(this) + if (udfpsViewPerformance()) { + if (this.parent != null) { + windowManager.removeView(this) + } + Trace.setCounter("UdfpsAddView", 0) + } else { + windowManager.removeView(this) + } setOnTouchListener(null) setOnHoverListener(null) overlayTouchListener?.let { @@ -423,7 +436,7 @@ class UdfpsControllerOverlay @JvmOverloads constructor( overlayViewLegacy = null overlayTouchView = null overlayTouchListener = null - listenForAsleepJob?.cancel() + listenForCurrentKeyguardState?.cancel() return wasShowing } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt index ae1539ebaf89..59b59bf1e437 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt @@ -50,6 +50,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.withContext @@ -64,13 +65,16 @@ interface FacePropertyRepository { /** The current face sensor location in current device rotation */ val sensorLocation: StateFlow<Point?> + + /** The info of current available camera. */ + val cameraInfo: StateFlow<CameraInfo?> } /** Describes a biometric sensor */ data class FaceSensorInfo(val id: Int, val strength: SensorStrength) /** Data class for camera info */ -private data class CameraInfo( +data class CameraInfo( /** The logical id of the camera */ val cameraId: String, /** The physical id of the camera */ @@ -124,7 +128,7 @@ constructor( private val cameraInfoList: List<CameraInfo> = loadCameraInfoList() private var currentPhysicalCameraId: String? = null - private val defaultSensorLocation: StateFlow<Point?> = + override val cameraInfo: StateFlow<CameraInfo?> = ConflatedCallbackFlow.conflatedCallbackFlow { val callback = object : CameraManager.AvailabilityCallback() { @@ -142,7 +146,7 @@ constructor( physicalCameraId == it.cameraPhysicalId } trySendWithFailureLogging( - cameraInfo?.cameraLocation, + cameraInfo, TAG, "Update face sensor location to $cameraInfo." ) @@ -168,7 +172,7 @@ constructor( } currentPhysicalCameraId = cameraInfo?.cameraPhysicalId trySendWithFailureLogging( - cameraInfo?.cameraLocation, + cameraInfo, TAG, "Update face sensor location to $cameraInfo." ) @@ -181,8 +185,16 @@ constructor( .stateIn( applicationScope, started = SharingStarted.WhileSubscribed(), - initialValue = - if (cameraInfoList.isNotEmpty()) cameraInfoList[0].cameraLocation else null + initialValue = if (cameraInfoList.isNotEmpty()) cameraInfoList[0] else null + ) + + private val defaultSensorLocation: StateFlow<Point?> = + cameraInfo + .map { it?.cameraLocation } + .stateIn( + applicationScope, + started = SharingStarted.WhileSubscribed(), + initialValue = null ) override val sensorLocation: StateFlow<Point?> = diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt index b0cc3bd807dd..cd5b12482d83 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt @@ -438,9 +438,20 @@ object BiometricViewBinder { // Play haptics launch { - viewModel.hapticsToPlay.collect { hapticFeedbackConstant -> - if (hapticFeedbackConstant != HapticFeedbackConstants.NO_HAPTICS) { - vibratorHelper.performHapticFeedback(view, hapticFeedbackConstant) + viewModel.hapticsToPlay.collect { haptics -> + if (haptics.hapticFeedbackConstant != HapticFeedbackConstants.NO_HAPTICS) { + if (haptics.flag != null) { + vibratorHelper.performHapticFeedback( + view, + haptics.hapticFeedbackConstant, + haptics.flag, + ) + } else { + vibratorHelper.performHapticFeedback( + view, + haptics.hapticFeedbackConstant, + ) + } viewModel.clearHaptics() } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index 788991d2e45b..c933e0e31d40 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -53,6 +53,7 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch /** ViewModel for BiometricPrompt. */ @@ -144,9 +145,10 @@ constructor( private val _forceLargeSize = MutableStateFlow(false) private val _forceMediumSize = MutableStateFlow(false) - private val _hapticsToPlay = MutableStateFlow(HapticFeedbackConstants.NO_HAPTICS) + private val _hapticsToPlay = + MutableStateFlow(HapticsToPlay(HapticFeedbackConstants.NO_HAPTICS, /* flag= */ null)) - /** Event fired to the view indicating a [HapticFeedbackConstants] to be played */ + /** Event fired to the view indicating a [HapticsToPlay] */ val hapticsToPlay = _hapticsToPlay.asStateFlow() /** The current position of the prompt */ @@ -686,16 +688,26 @@ constructor( } private fun vibrateOnSuccess() { - _hapticsToPlay.value = HapticFeedbackConstants.CONFIRM + _hapticsToPlay.value = + HapticsToPlay( + HapticFeedbackConstants.CONFIRM, + HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING, + ) } private fun vibrateOnError() { - _hapticsToPlay.value = HapticFeedbackConstants.REJECT + _hapticsToPlay.value = + HapticsToPlay( + HapticFeedbackConstants.REJECT, + HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING, + ) } - /** Clears the [hapticsToPlay] variable by setting it to the NO_HAPTICS default. */ + /** Clears the [hapticsToPlay] variable by setting its constant to the NO_HAPTICS default. */ fun clearHaptics() { - _hapticsToPlay.value = HapticFeedbackConstants.NO_HAPTICS + _hapticsToPlay.update { previous -> + HapticsToPlay(HapticFeedbackConstants.NO_HAPTICS, previous.flag) + } } companion object { @@ -724,3 +736,9 @@ enum class FingerprintStartMode { val isStarted: Boolean get() = this == Normal || this == Delayed } + +/** + * The state of haptic feedback to play. It is composed by a [HapticFeedbackConstants] and a + * [HapticFeedbackConstants] flag. + */ +data class HapticsToPlay(val hapticFeedbackConstant: Int, val flag: Int?) diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt index f7ba5a44f4c9..8397372e0735 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt @@ -88,7 +88,6 @@ constructor( val docked = dockManager.isDocked return when { - to == KeyguardState.DREAMING -> CommunalSceneKey.Blank docked && to == KeyguardState.LOCKSCREEN && from != KeyguardState.GLANCEABLE_HUB -> { CommunalSceneKey.Communal } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt index 5d525413a919..151e1eeaefc5 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt @@ -24,6 +24,7 @@ import com.android.systemui.communal.data.repository.CommunalPrefsRepository import com.android.systemui.communal.data.repository.CommunalRepository import com.android.systemui.communal.data.repository.CommunalWidgetRepository import com.android.systemui.communal.domain.model.CommunalContentModel +import com.android.systemui.communal.domain.model.CommunalContentModel.WidgetContent import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.shared.model.CommunalContentSize.FULL import com.android.systemui.communal.shared.model.CommunalContentSize.HALF @@ -278,14 +279,25 @@ constructor( } /** A list of widget content to be displayed in the communal hub. */ - val widgetContent: Flow<List<CommunalContentModel.Widget>> = - widgetRepository.communalWidgets.map { widgets -> - filterWidgetsByExistingUsers(widgets).map Widget@{ widget -> - return@Widget CommunalContentModel.Widget( - appWidgetId = widget.appWidgetId, - providerInfo = widget.providerInfo, - appWidgetHost = appWidgetHost, - ) + val widgetContent: Flow<List<WidgetContent>> = + combine( + widgetRepository.communalWidgets.map { filterWidgetsByExistingUsers(it) }, + communalSettingsInteractor.communalWidgetCategories + ) { widgets, allowedCategories -> + widgets.map { widget -> + if (widget.providerInfo.widgetCategory and allowedCategories != 0) { + // At least one category this widget specified is allowed, so show it + WidgetContent.Widget( + appWidgetId = widget.appWidgetId, + providerInfo = widget.providerInfo, + appWidgetHost = appWidgetHost, + ) + } else { + WidgetContent.DisabledWidget( + appWidgetId = widget.appWidgetId, + providerInfo = widget.providerInfo, + ) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt index ae019a187bae..c64f666ebf10 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt @@ -18,6 +18,7 @@ package com.android.systemui.communal.domain.model import android.appwidget.AppWidgetProviderInfo import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE +import android.content.pm.ApplicationInfo import android.widget.RemoteViews import com.android.systemui.communal.shared.model.CommunalContentSize import com.android.systemui.communal.widgets.CommunalAppWidgetHost @@ -42,20 +43,37 @@ sealed interface CommunalContentModel { val createdTimestampMillis: Long } - data class Widget( - val appWidgetId: Int, - val providerInfo: AppWidgetProviderInfo, - val appWidgetHost: CommunalAppWidgetHost, - ) : CommunalContentModel { - override val key = KEY.widget(appWidgetId) - // Widget size is always half. - override val size = CommunalContentSize.HALF + sealed interface WidgetContent : CommunalContentModel { + val appWidgetId: Int + val providerInfo: AppWidgetProviderInfo + + data class Widget( + override val appWidgetId: Int, + override val providerInfo: AppWidgetProviderInfo, + val appWidgetHost: CommunalAppWidgetHost, + ) : WidgetContent { + override val key = KEY.widget(appWidgetId) + // Widget size is always half. + override val size = CommunalContentSize.HALF + + /** Whether this widget can be reconfigured after it has already been added. */ + val reconfigurable: Boolean + get() = + (providerInfo.widgetFeatures and WIDGET_FEATURE_RECONFIGURABLE != 0) && + providerInfo.configure != null + } + + data class DisabledWidget( + override val appWidgetId: Int, + override val providerInfo: AppWidgetProviderInfo + ) : WidgetContent { + override val key = KEY.disabledWidget(appWidgetId) + // Widget size is always half. + override val size = CommunalContentSize.HALF - /** Whether this widget can be reconfigured after it has already been added. */ - val reconfigurable: Boolean - get() = - (providerInfo.widgetFeatures and WIDGET_FEATURE_RECONFIGURABLE != 0) && - providerInfo.configure != null + val appInfo: ApplicationInfo? + get() = providerInfo.providerInfo?.applicationInfo + } } /** A placeholder item representing a new widget being added */ @@ -111,6 +129,10 @@ sealed interface CommunalContentModel { return "widget_$id" } + fun disabledWidget(id: Int): String { + return "disabled_widget_$id" + } + fun widgetPlaceholder(): String { return "widget_placeholder_${UUID.randomUUID()}" } @@ -129,5 +151,5 @@ sealed interface CommunalContentModel { } } - fun isWidget() = this is Widget + fun isWidgetContent() = this is WidgetContent } diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt index 080dbedcb350..93e2b37cfe87 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt @@ -21,6 +21,7 @@ import android.appwidget.AppWidgetProviderInfo import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_CONFIGURATION_OPTIONAL import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE import android.content.ComponentName +import android.os.Bundle import android.os.UserHandle import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.Logger @@ -56,6 +57,7 @@ constructor( return widgetInfo.configure != null && !configurationOptional } } + private val logger = Logger(logBuffer, TAG) /** @@ -84,9 +86,16 @@ constructor( private fun bindWidget(widgetId: Int, user: UserHandle, provider: ComponentName): Boolean { if (appWidgetManager.isPresent) { + val options = + Bundle().apply { + putInt( + AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, + AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD, + ) + } return appWidgetManager .get() - .bindAppWidgetIdIfAllowed(widgetId, user, provider, /* options */ null) + .bindAppWidgetIdIfAllowed(widgetId, user, provider, options) } return false } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt index e8a84449566d..7f8103e63684 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt @@ -18,7 +18,7 @@ package com.android.systemui.controls.ui import android.app.Activity import android.app.ActivityOptions -import android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED +import android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED import android.app.Dialog import android.app.PendingIntent import android.content.ComponentName diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java index 6d9994fb2205..ce24259bbc1e 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java @@ -71,6 +71,7 @@ import android.media.MediaRouter2Manager; import android.media.projection.IMediaProjectionManager; import android.media.projection.MediaProjectionManager; import android.media.session.MediaSessionManager; +import android.nearby.NearbyManager; import android.net.ConnectivityManager; import android.net.NetworkScoreManager; import android.net.wifi.WifiManager; @@ -441,6 +442,12 @@ public class FrameworkServicesModule { @Provides @Singleton + static NearbyManager provideNearbyManager(Context context) { + return context.getSystemService(NearbyManager.class); + } + + @Provides + @Singleton static NetworkScoreManager provideNetworkScoreManager(Context context) { return context.getSystemService(NetworkScoreManager.class); } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java index a90980fddfb0..a431a59fcef6 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java @@ -16,7 +16,6 @@ package com.android.systemui.dagger; -import com.android.systemui.globalactions.ShutdownUiModule; import com.android.systemui.keyguard.CustomizationProvider; import com.android.systemui.statusbar.NotificationInsetsModule; import com.android.systemui.statusbar.QsFrameTranslateModule; @@ -32,7 +31,6 @@ import dagger.Subcomponent; DependencyProvider.class, NotificationInsetsModule.class, QsFrameTranslateModule.class, - ShutdownUiModule.class, SystemUIBinder.class, SystemUIModule.class, SystemUICoreStartableModule.class, diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt index cf91e147d1b3..0c9fbc27cc5d 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt @@ -189,6 +189,18 @@ constructor( } } .launchIn(applicationScope) + + facePropertyRepository.cameraInfo + .onEach { + if (it != null && isRunning()) { + repository.cancel() + runFaceAuth( + FaceAuthUiEvent.FACE_AUTH_CAMERA_AVAILABLE_CHANGED, + fallbackToDetect = true + ) + } + } + .launchIn(applicationScope) } private suspend fun resetLockedOutState(currentUserId: Int) { diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt index ee220d5fb713..08a6166fe557 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt @@ -31,6 +31,7 @@ import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.ALTERNATE import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.ASSISTANT_VISIBILITY_CHANGED import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.AUTH_REQUEST_DURING_CANCELLATION import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.BIOMETRIC_ENABLED +import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.CAMERA_AVAILABLE_CHANGED import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.CAMERA_LAUNCHED import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.DEVICE_WOKEN_UP_ON_REACH_GESTURE import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.DISPLAY_OFF @@ -130,6 +131,7 @@ private object InternalFaceAuthReasons { "Face auth stopped because non strong biometric allowed changed" const val POSTURE_CHANGED = "Face auth started/stopped due to device posture changed." const val DISPLAY_OFF = "Face auth stopped due to display state OFF." + const val CAMERA_AVAILABLE_CHANGED = "Face auth started due to the available camera changed" } /** @@ -221,7 +223,9 @@ constructor(private val id: Int, val reason: String, var extraInfo: Int = 0) : @UiEvent(doc = NON_STRONG_BIOMETRIC_ALLOWED_CHANGED) FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED(1256, NON_STRONG_BIOMETRIC_ALLOWED_CHANGED), @UiEvent(doc = ACCESSIBILITY_ACTION) FACE_AUTH_ACCESSIBILITY_ACTION(1454, ACCESSIBILITY_ACTION), - @UiEvent(doc = DISPLAY_OFF) FACE_AUTH_DISPLAY_OFF(1461, DISPLAY_OFF); + @UiEvent(doc = DISPLAY_OFF) FACE_AUTH_DISPLAY_OFF(1461, DISPLAY_OFF), + @UiEvent(doc = CAMERA_AVAILABLE_CHANGED) + FACE_AUTH_CAMERA_AVAILABLE_CHANGED(1623, CAMERA_AVAILABLE_CHANGED); override fun getId(): Int = this.id diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt index 9000da33312c..b97bace9584f 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt @@ -40,7 +40,6 @@ import com.android.systemui.log.core.Logger import com.android.systemui.log.dagger.DreamLog import com.android.systemui.statusbar.BlurUtils import com.android.systemui.statusbar.CrossFadeHelper -import com.android.systemui.statusbar.policy.ConfigurationController import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.launch @@ -55,7 +54,6 @@ constructor( private val mOverlayStateController: DreamOverlayStateController, @Named(DreamOverlayModule.DREAM_BLUR_RADIUS) private val mDreamBlurRadius: Int, private val dreamOverlayViewModel: DreamOverlayViewModel, - private val configController: ConfigurationController, @Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DURATION) private val mDreamInBlurAnimDurationMs: Long, @Named(DreamOverlayModule.DREAM_IN_COMPLICATIONS_ANIMATION_DURATION) diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt index dd67a4c8706c..bd99f4b8230e 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt @@ -20,6 +20,7 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel import com.android.systemui.res.R import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -33,16 +34,16 @@ class DreamOverlayViewModel @Inject constructor( configurationInteractor: ConfigurationInteractor, - private val toGlanceableHubTransitionViewModel: DreamingToGlanceableHubTransitionViewModel, + toGlanceableHubTransitionViewModel: DreamingToGlanceableHubTransitionViewModel, + fromGlanceableHubTransitionInteractor: GlanceableHubToDreamingTransitionViewModel, private val toLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel, ) { val dreamOverlayTranslationX: Flow<Float> = - configurationInteractor - .dimensionPixelSize(R.dimen.dream_overlay_exit_x_offset) - .flatMapLatest { px: Int -> - toGlanceableHubTransitionViewModel.dreamOverlayTranslationX(px) - } + merge( + toGlanceableHubTransitionViewModel.dreamOverlayTranslationX, + fromGlanceableHubTransitionInteractor.dreamOverlayTranslationX, + ) val dreamOverlayTranslationY: Flow<Float> = configurationInteractor @@ -55,6 +56,7 @@ constructor( merge( toLockscreenTransitionViewModel.dreamOverlayAlpha, toGlanceableHubTransitionViewModel.dreamOverlayAlpha, + fromGlanceableHubTransitionInteractor.dreamOverlayAlpha, ) val transitionEnded = toLockscreenTransitionViewModel.transitionEnded diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt index 7a24d7693035..298da1359728 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt @@ -22,8 +22,10 @@ import com.android.server.notification.Flags.FLAG_VIBRATE_WHILE_UNLOCKED import com.android.server.notification.Flags.crossAppPoliteNotifications import com.android.server.notification.Flags.politeNotifications import com.android.server.notification.Flags.vibrateWhileUnlocked +import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.Flags.FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR import com.android.systemui.Flags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT +import com.android.systemui.Flags.communalHub import com.android.systemui.Flags.keyguardBottomAreaRefactor import com.android.systemui.Flags.migrateClocksToBlueprint import com.android.systemui.dagger.SysUISingleton @@ -58,6 +60,9 @@ class FlagDependencies @Inject constructor(featureFlags: FeatureFlagsClassic, ha // ComposeLockscreen dependencies ComposeLockscreen.token dependsOn keyguardBottomAreaRefactor ComposeLockscreen.token dependsOn migrateClocksToBlueprint + + // CommunalHub dependencies + communalHub dependsOn migrateClocksToBlueprint } private inline val politeNotifications @@ -70,4 +75,6 @@ class FlagDependencies @Inject constructor(featureFlags: FeatureFlagsClassic, ha get() = FlagToken(FLAG_KEYGUARD_BOTTOM_AREA_REFACTOR, keyguardBottomAreaRefactor()) private inline val migrateClocksToBlueprint get() = FlagToken(FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT, migrateClocksToBlueprint()) + private inline val communalHub + get() = FlagToken(FLAG_COMMUNAL_HUB, communalHub()) } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 33a69bf0d774..6bb846491224 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -369,12 +369,6 @@ object Flags { @Keep val WM_BUBBLE_BAR = sysPropBooleanFlag("persist.wm.debug.bubble_bar", default = false) - // TODO(b/260271148): Tracking bug - @Keep - @JvmField - val WM_DESKTOP_WINDOWING_2 = - sysPropBooleanFlag("persist.wm.debug.desktop_mode_2", default = false) - // TODO(b/254513207): Tracking Bug to delete @Keep @JvmField diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java index 51978ece14db..ccd69ca55f0c 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java @@ -22,7 +22,10 @@ import android.annotation.Nullable; import android.annotation.StringRes; import android.app.Dialog; import android.content.Context; +import android.nearby.NearbyManager; +import android.net.platform.flags.Flags; import android.os.PowerManager; +import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.Window; @@ -38,6 +41,8 @@ import com.android.systemui.scrim.ScrimDrawable; import com.android.systemui.statusbar.BlurUtils; import com.android.systemui.statusbar.phone.ScrimController; +import javax.inject.Inject; + /** * Provides the UI shown during system shutdown. */ @@ -45,9 +50,13 @@ public class ShutdownUi { private Context mContext; private BlurUtils mBlurUtils; - public ShutdownUi(Context context, BlurUtils blurUtils) { + private NearbyManager mNearbyManager; + + @Inject + public ShutdownUi(Context context, BlurUtils blurUtils, NearbyManager nearbyManager) { mContext = context; mBlurUtils = blurUtils; + mNearbyManager = nearbyManager; } /** @@ -132,12 +141,28 @@ public class ShutdownUi { /** * Returns the layout resource to use for UI while shutting down. * @param isReboot Whether this is a reboot or a shutdown. - * @return */ - public int getShutdownDialogContent(boolean isReboot) { - return R.layout.shutdown_dialog; + @VisibleForTesting int getShutdownDialogContent(boolean isReboot) { + if (!Flags.poweredOffFindingPlatform()) { + return R.layout.shutdown_dialog; + } + int finderActive = mNearbyManager.getPoweredOffFindingMode(); + if (finderActive == NearbyManager.POWERED_OFF_FINDING_MODE_DISABLED + || finderActive == NearbyManager.POWERED_OFF_FINDING_MODE_UNSUPPORTED) { + // inactive or unsupported, use regular shutdown dialog + return R.layout.shutdown_dialog; + } else if (finderActive == NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED) { + // active, use dialog with finder info if shutting down + return isReboot ? R.layout.shutdown_dialog : + com.android.systemui.res.R.layout.shutdown_dialog_finder_active; + } else { + // that's weird? default to regular dialog + Log.w("ShutdownUi", "Unexpected value for finder active: " + finderActive); + return R.layout.shutdown_dialog; + } } + @StringRes @VisibleForTesting int getRebootMessage(boolean isReboot, @Nullable String reason) { if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index c6b99528b2ba..6d917bbde82b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -40,6 +40,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE; import static com.android.systemui.DejankUtils.whitelistIpcs; +import static com.android.systemui.Flags.notifyPowerManagerUserActivityBackground; import static com.android.systemui.Flags.refactorGetCurrentUser; import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS; import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; @@ -1488,7 +1489,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } public void userActivity() { - mPM.userActivity(mSystemClock.uptimeMillis(), false); + if (notifyPowerManagerUserActivityBackground()) { + mUiBgExecutor.execute(() -> mPM.userActivity(mSystemClock.uptimeMillis(), false)); + } else { + mPM.userActivity(mSystemClock.uptimeMillis(), false); + } } private void setupLocked() { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt index b152eea63028..2bede977c958 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt @@ -40,6 +40,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.buffer import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.shareIn @@ -177,92 +178,99 @@ constructor( // TODO(b/322555228) Remove after consolidating device entry auth messages with BP auth messages // in BiometricStatusRepository + /** + * FingerprintAuthenticationStatus Multiple statuses may arrive in immediate sequence (ie: + * acquired, failed, help, error), so we use a buffer to ensure consumers receive each distinct + * status. + */ override val authenticationStatus: Flow<FingerprintAuthenticationStatus> - get() = conflatedCallbackFlow { - val callback = - object : KeyguardUpdateMonitorCallback() { - override fun onBiometricAuthenticated( - userId: Int, - biometricSourceType: BiometricSourceType, - isStrongBiometric: Boolean, - ) { - sendUpdateIfFingerprint( - biometricSourceType, - SuccessFingerprintAuthenticationStatus( - userId, - isStrongBiometric, - ), - ) - } + get() = + conflatedCallbackFlow { + val callback = + object : KeyguardUpdateMonitorCallback() { + override fun onBiometricAuthenticated( + userId: Int, + biometricSourceType: BiometricSourceType, + isStrongBiometric: Boolean, + ) { + sendUpdateIfFingerprint( + biometricSourceType, + SuccessFingerprintAuthenticationStatus( + userId, + isStrongBiometric, + ), + ) + } - override fun onBiometricError( - msgId: Int, - errString: String?, - biometricSourceType: BiometricSourceType, - ) { - sendUpdateIfFingerprint( - biometricSourceType, - ErrorFingerprintAuthenticationStatus( - msgId, - errString, - ), - ) - } + override fun onBiometricError( + msgId: Int, + errString: String?, + biometricSourceType: BiometricSourceType, + ) { + sendUpdateIfFingerprint( + biometricSourceType, + ErrorFingerprintAuthenticationStatus( + msgId, + errString, + ), + ) + } - override fun onBiometricHelp( - msgId: Int, - helpString: String?, - biometricSourceType: BiometricSourceType, - ) { - sendUpdateIfFingerprint( - biometricSourceType, - HelpFingerprintAuthenticationStatus( - msgId, - helpString, - ), - ) - } + override fun onBiometricHelp( + msgId: Int, + helpString: String?, + biometricSourceType: BiometricSourceType, + ) { + sendUpdateIfFingerprint( + biometricSourceType, + HelpFingerprintAuthenticationStatus( + msgId, + helpString, + ), + ) + } - override fun onBiometricAuthFailed( - biometricSourceType: BiometricSourceType, - ) { - sendUpdateIfFingerprint( - biometricSourceType, - FailFingerprintAuthenticationStatus, - ) - } + override fun onBiometricAuthFailed( + biometricSourceType: BiometricSourceType, + ) { + sendUpdateIfFingerprint( + biometricSourceType, + FailFingerprintAuthenticationStatus, + ) + } - override fun onBiometricAcquired( - biometricSourceType: BiometricSourceType, - acquireInfo: Int, - ) { - sendUpdateIfFingerprint( - biometricSourceType, - AcquiredFingerprintAuthenticationStatus( - AuthenticationReason.DeviceEntryAuthentication, - acquireInfo - ), - ) - } + override fun onBiometricAcquired( + biometricSourceType: BiometricSourceType, + acquireInfo: Int, + ) { + sendUpdateIfFingerprint( + biometricSourceType, + AcquiredFingerprintAuthenticationStatus( + AuthenticationReason.DeviceEntryAuthentication, + acquireInfo + ), + ) + } - private fun sendUpdateIfFingerprint( - biometricSourceType: BiometricSourceType, - authenticationStatus: FingerprintAuthenticationStatus - ) { - if (biometricSourceType != BiometricSourceType.FINGERPRINT) { - return - } + private fun sendUpdateIfFingerprint( + biometricSourceType: BiometricSourceType, + authenticationStatus: FingerprintAuthenticationStatus + ) { + if (biometricSourceType != BiometricSourceType.FINGERPRINT) { + return + } - trySendWithFailureLogging( - authenticationStatus, - TAG, - "new fingerprint authentication status" - ) - } + trySendWithFailureLogging( + authenticationStatus, + TAG, + "new fingerprint authentication status" + ) + } + } + keyguardUpdateMonitor.registerCallback(callback) + awaitClose { keyguardUpdateMonitor.removeCallback(callback) } } - keyguardUpdateMonitor.registerCallback(callback) - awaitClose { keyguardUpdateMonitor.removeCallback(callback) } - } + .buffer(capacity = 4) override val shouldUpdateIndicatorVisibility: Flow<Boolean> = conflatedCallbackFlow { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt index 59288a155666..0ea53906b7f8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt @@ -41,7 +41,6 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.callbackFlow -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onStart @@ -111,7 +110,6 @@ constructor( awaitClose { clockRegistry.unregisterClockChangeListener(listener) } } .mapNotNull { it } - .distinctUntilChanged() override val currentClock: StateFlow<ClockController?> = currentClockId diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt index 0cf74a1ff32e..9fc36923b04d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt @@ -156,5 +156,6 @@ constructor( val TO_GONE_DURATION = 500.milliseconds val TO_AOD_DURATION = TRANSITION_DURATION_MS val TO_PRIMARY_BOUNCER_DURATION = TRANSITION_DURATION_MS + val TO_DOZING_DURATION = TRANSITION_DURATION_MS } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt index e2a8b6c53daa..54d5908e9fa4 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt @@ -115,5 +115,7 @@ constructor( const val TAG = "FromDozingTransitionInteractor" private val DEFAULT_DURATION = 500.milliseconds val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION + val TO_GONE_DURATION = DEFAULT_DURATION + val TO_PRIMARY_BOUNCER_DURATION = DEFAULT_DURATION } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt index c6594ef317d6..acfa107cc1f1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt @@ -18,6 +18,7 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import com.android.app.animation.Interpolators +import com.android.app.tracing.coroutines.launch import com.android.systemui.Flags.communalHub import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background @@ -64,12 +65,13 @@ constructor( private fun listenForDreamingToGlanceableHub() { if (!communalHub()) return - glanceableHubTransitions.listenForGlanceableHubTransition( - transitionName = "listenForDreamingToGlanceableHub", - transitionOwnerName = TAG, - fromState = KeyguardState.DREAMING, - toState = KeyguardState.GLANCEABLE_HUB, - ) + scope.launch("$TAG#listenForDreamingToGlanceableHub", mainDispatcher) { + glanceableHubTransitions.listenForGlanceableHubTransition( + transitionOwnerName = TAG, + fromState = KeyguardState.DREAMING, + toState = KeyguardState.GLANCEABLE_HUB, + ) + } } fun startToLockscreenTransition() { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt index fbf195eb0952..786c3c6697d9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt @@ -27,13 +27,16 @@ import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled import com.android.systemui.power.domain.interactor.PowerInteractor -import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleMultiple +import com.android.systemui.util.kotlin.BooleanFlowOperators.and +import com.android.systemui.util.kotlin.BooleanFlowOperators.not import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext @SysUISingleton class FromGlanceableHubTransitionInteractor @@ -58,13 +61,12 @@ constructor( if (!Flags.communalHub()) { return } - listenForHubToLockscreen() + listenForHubToLockscreenOrDreaming() listenForHubToDozing() listenForHubToPrimaryBouncer() listenForHubToAlternateBouncer() listenForHubToOccluded() listenForHubToGone() - listenForHubToDreaming() } override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator { @@ -82,13 +84,24 @@ constructor( * Listens for the glanceable hub transition to lock screen and directly drives the keyguard * transition. */ - private fun listenForHubToLockscreen() { - glanceableHubTransitions.listenForGlanceableHubTransition( - transitionName = "listenForHubToLockscreen", - transitionOwnerName = TAG, - fromState = KeyguardState.GLANCEABLE_HUB, - toState = KeyguardState.LOCKSCREEN, - ) + private fun listenForHubToLockscreenOrDreaming() { + scope.launch("$TAG#listenForGlanceableHubToLockscreenOrDream") { + keyguardInteractor.isDreaming.collectLatest { dreaming -> + withContext(mainDispatcher) { + val toState = + if (dreaming) { + KeyguardState.DREAMING + } else { + KeyguardState.LOCKSCREEN + } + glanceableHubTransitions.listenForGlanceableHubTransition( + transitionOwnerName = TAG, + fromState = KeyguardState.GLANCEABLE_HUB, + toState = toState, + ) + } + } + } } private fun listenForHubToPrimaryBouncer() { @@ -137,31 +150,15 @@ constructor( } } - private fun listenForHubToDreaming() { - val invalidFromStates = setOf(KeyguardState.AOD, KeyguardState.DOZING) - scope.launch("$TAG#listenForHubToDreaming") { - keyguardInteractor.isAbleToDream - .sampleMultiple(startedKeyguardTransitionStep, finishedKeyguardState) - .collect { (isAbleToDream, lastStartedTransition, finishedKeyguardState) -> - val isOnHub = finishedKeyguardState == KeyguardState.GLANCEABLE_HUB - val isTransitionInterruptible = - lastStartedTransition.to == KeyguardState.GLANCEABLE_HUB && - !invalidFromStates.contains(lastStartedTransition.from) - if (isAbleToDream && (isOnHub || isTransitionInterruptible)) { - startTransitionTo(KeyguardState.DREAMING) - } - } - } - } - private fun listenForHubToOccluded() { scope.launch { - keyguardInteractor.isKeyguardOccluded.sample(startedKeyguardState, ::Pair).collect { - (isOccluded, keyguardState) -> - if (isOccluded && keyguardState == fromState) { - startTransitionTo(KeyguardState.OCCLUDED) + and(keyguardInteractor.isKeyguardOccluded, not(keyguardInteractor.isDreaming)) + .sample(startedKeyguardState, ::Pair) + .collect { (isOccludedAndNotDreaming, keyguardState) -> + if (isOccludedAndNotDreaming && keyguardState == fromState) { + startTransitionTo(KeyguardState.OCCLUDED) + } } - } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt index 40b2c638823d..7263ae96b3a8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt @@ -360,13 +360,13 @@ constructor( if (!com.android.systemui.Flags.communalHub()) { return } - - glanceableHubTransitions.listenForGlanceableHubTransition( - transitionName = "listenForLockscreenToGlanceableHub", - transitionOwnerName = TAG, - fromState = KeyguardState.LOCKSCREEN, - toState = KeyguardState.GLANCEABLE_HUB, - ) + scope.launch(mainDispatcher) { + glanceableHubTransitions.listenForGlanceableHubTransition( + transitionOwnerName = TAG, + fromState = KeyguardState.LOCKSCREEN, + toState = KeyguardState.GLANCEABLE_HUB, + ) + } } override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt index f45a9ecfaedf..c5a28463bf7e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt @@ -274,5 +274,6 @@ constructor( val TO_GONE_SHORT_DURATION = 200.milliseconds val TO_AOD_DURATION = DEFAULT_DURATION val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION + val TO_DOZING_DURATION = DEFAULT_DURATION } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt index 809c0aee9882..6cb1eb493db3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt @@ -18,11 +18,9 @@ package com.android.systemui.keyguard.domain.interactor import android.animation.ValueAnimator import com.android.app.animation.Interpolators -import com.android.app.tracing.coroutines.launch import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalTransitionProgress import com.android.systemui.communal.shared.model.CommunalSceneKey -import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState @@ -32,13 +30,11 @@ import com.android.systemui.util.kotlin.sample import java.util.UUID import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.flowOn class GlanceableHubTransitions @Inject constructor( - @Application private val scope: CoroutineScope, @Background private val bgDispatcher: CoroutineDispatcher, private val transitionInteractor: KeyguardTransitionInteractor, private val transitionRepository: KeyguardTransitionRepository, @@ -52,105 +48,101 @@ constructor( * externally. The progress is used for both transitions caused by user touch input or by * programmatic changes. */ - fun listenForGlanceableHubTransition( - transitionName: String, + suspend fun listenForGlanceableHubTransition( transitionOwnerName: String, fromState: KeyguardState, toState: KeyguardState, ) { val toScene = - if (toState == KeyguardState.GLANCEABLE_HUB) { - CommunalSceneKey.Communal - } else { + if (fromState == KeyguardState.GLANCEABLE_HUB) { CommunalSceneKey.Blank + } else { + CommunalSceneKey.Communal } var transitionId: UUID? = null - scope.launch("$transitionOwnerName#$transitionName") { - communalInteractor - .transitionProgressToScene(toScene) - .sample( - transitionInteractor.startedKeyguardTransitionStep.flowOn(bgDispatcher), - ::Pair - ) - .collect { pair -> - val (transitionProgress, lastStartedStep) = pair - val id = transitionId - if (id == null) { - // No transition started. - if ( - transitionProgress is CommunalTransitionProgress.Transition && - lastStartedStep.to == fromState - ) { - transitionId = - transitionRepository.startTransition( - TransitionInfo( - ownerName = transitionOwnerName, - from = fromState, - to = toState, - animator = null, // transition will be manually controlled - ) + communalInteractor + .transitionProgressToScene(toScene) + .sample( + transitionInteractor.startedKeyguardTransitionStep.flowOn(bgDispatcher), + ::Pair, + ) + .collect { (transitionProgress, lastStartedStep) -> + val id = transitionId + if (id == null) { + // No transition started. + if ( + transitionProgress is CommunalTransitionProgress.Transition && + lastStartedStep.to == fromState + ) { + transitionId = + transitionRepository.startTransition( + TransitionInfo( + ownerName = transitionOwnerName, + from = fromState, + to = toState, + animator = null, // transition will be manually controlled ) - } - } else { - if (lastStartedStep.to != toState) { - return@collect - } - // An existing `id` means a transition is started, and calls to - // `updateTransition` will control it until FINISHED or CANCELED - val nextState: TransitionState - val progressFraction: Float - when (transitionProgress) { - is CommunalTransitionProgress.Idle -> { - if (transitionProgress.scene == toScene) { - nextState = TransitionState.FINISHED - progressFraction = 1f - } else { - nextState = TransitionState.CANCELED - progressFraction = 0f - } - } - is CommunalTransitionProgress.Transition -> { - nextState = TransitionState.RUNNING - progressFraction = transitionProgress.progress - } - is CommunalTransitionProgress.OtherTransition -> { - // Shouldn't happen but if another transition starts during the - // current one, mark the current one as canceled. + ) + } + } else { + if (lastStartedStep.to != toState) { + return@collect + } + // An existing `id` means a transition is started, and calls to + // `updateTransition` will control it until FINISHED or CANCELED + val nextState: TransitionState + val progressFraction: Float + when (transitionProgress) { + is CommunalTransitionProgress.Idle -> { + if (transitionProgress.scene == toScene) { + nextState = TransitionState.FINISHED + progressFraction = 1f + } else { nextState = TransitionState.CANCELED progressFraction = 0f } } - transitionRepository.updateTransition( - id, - progressFraction, - nextState, - ) - - if ( - nextState == TransitionState.CANCELED || - nextState == TransitionState.FINISHED - ) { - transitionId = null + is CommunalTransitionProgress.Transition -> { + nextState = TransitionState.RUNNING + progressFraction = transitionProgress.progress } + is CommunalTransitionProgress.OtherTransition -> { + // Shouldn't happen but if another transition starts during the + // current one, mark the current one as canceled. + nextState = TransitionState.CANCELED + progressFraction = 0f + } + } + transitionRepository.updateTransition( + id, + progressFraction, + nextState, + ) - // If canceled, just put the state back. - if (nextState == TransitionState.CANCELED) { - transitionRepository.startTransition( - TransitionInfo( - ownerName = transitionOwnerName, - from = toState, - to = fromState, - animator = - ValueAnimator().apply { - interpolator = Interpolators.LINEAR - duration = 0 - } - ) + if ( + nextState == TransitionState.CANCELED || + nextState == TransitionState.FINISHED + ) { + transitionId = null + } + + // If canceled, just put the state back. + if (nextState == TransitionState.CANCELED) { + transitionRepository.startTransition( + TransitionInfo( + ownerName = transitionOwnerName, + from = toState, + to = fromState, + animator = + ValueAnimator().apply { + interpolator = Interpolators.LINEAR + duration = 0 + } ) - } + ) } } - } + } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt index d1fd7195d8cc..719edd7e8535 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt @@ -45,7 +45,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapLatest -import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.shareIn /** Encapsulates business-logic related to the keyguard transitions. */ @@ -177,10 +176,16 @@ constructor( * Lockscreen (0f). */ val dozeAmountTransition: Flow<TransitionStep> = - merge( - aodToLockscreenTransition.map { step -> step.copy(value = 1f - step.value) }, - lockscreenToAodTransition, - ) + repository.transitions + .filter { step -> step.from == AOD || step.to == AOD } + .map { step -> + if (step.from == AOD) { + step.copy(value = 1 - step.value) + } else { + step + } + } + .shareIn(scope, SharingStarted.Eagerly, replay = 1) /** The last [TransitionStep] with a [TransitionState] of STARTED */ val startedKeyguardTransitionStep: Flow<TransitionStep> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt index 873cc847fa60..f46a207b273a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt @@ -22,6 +22,7 @@ import android.content.res.ColorStateList import android.util.StateSet import android.view.HapticFeedbackConstants import android.view.View +import androidx.core.view.isInvisible import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.common.ui.view.LongPressHandlingView @@ -82,6 +83,11 @@ object DeviceEntryIconViewBinder { // of the transition. repeatOnLifecycle(Lifecycle.State.CREATED) { launch { + viewModel.isVisible.collect { isVisible -> + longPressHandlingView.isInvisible = !isVisible + } + } + launch { viewModel.isLongPressEnabled.collect { isEnabled -> longPressHandlingView.setLongPressHandlingEnabled(isEnabled) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt index 951df5aeb65c..1abf4a6e2f1c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt @@ -16,15 +16,20 @@ package com.android.systemui.keyguard.ui.transitions import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToAodTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToDozingTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToPrimaryBouncerTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.DozingToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.DozingToPrimaryBouncerTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.GoneToDozingTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GoneToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenToAodTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDozingTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGoneTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel @@ -32,6 +37,7 @@ import com.android.systemui.keyguard.ui.viewmodel.LockscreenToPrimaryBouncerTran import com.android.systemui.keyguard.ui.viewmodel.OccludedToAodTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToAodTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToDozingTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToLockscreenTransitionViewModel import dagger.Binds import dagger.Module @@ -49,6 +55,12 @@ abstract class DeviceEntryIconTransitionModule { @Binds @IntoSet + abstract fun alternateBouncerToDozing( + impl: AlternateBouncerToDozingTransitionViewModel + ): DeviceEntryIconTransition + + @Binds + @IntoSet abstract fun alternateBouncerToGone( impl: AlternateBouncerToGoneTransitionViewModel ): DeviceEntryIconTransition @@ -71,12 +83,22 @@ abstract class DeviceEntryIconTransitionModule { @Binds @IntoSet + abstract fun dozingToGone(impl: DozingToGoneTransitionViewModel): DeviceEntryIconTransition + + @Binds + @IntoSet abstract fun dozingToLockscreen( impl: DozingToLockscreenTransitionViewModel ): DeviceEntryIconTransition @Binds @IntoSet + abstract fun dozingToPrimaryBouncer( + impl: DozingToPrimaryBouncerTransitionViewModel + ): DeviceEntryIconTransition + + @Binds + @IntoSet abstract fun dreamingToLockscreen( impl: DreamingToLockscreenTransitionViewModel ): DeviceEntryIconTransition @@ -89,6 +111,12 @@ abstract class DeviceEntryIconTransitionModule { @Binds @IntoSet + abstract fun lockscreenToDozing( + impl: LockscreenToDozingTransitionViewModel + ): DeviceEntryIconTransition + + @Binds + @IntoSet abstract fun lockscreenToDreaming( impl: LockscreenToDreamingTransitionViewModel ): DeviceEntryIconTransition @@ -123,6 +151,10 @@ abstract class DeviceEntryIconTransitionModule { @Binds @IntoSet + abstract fun goneToDozing(impl: GoneToDozingTransitionViewModel): DeviceEntryIconTransition + + @Binds + @IntoSet abstract fun occludedToAod(impl: OccludedToAodTransitionViewModel): DeviceEntryIconTransition @Binds @@ -139,6 +171,12 @@ abstract class DeviceEntryIconTransitionModule { @Binds @IntoSet + abstract fun primaryBouncerToDozing( + impl: PrimaryBouncerToDozingTransitionViewModel + ): DeviceEntryIconTransition + + @Binds + @IntoSet abstract fun primaryBouncerToLockscreen( impl: PrimaryBouncerToLockscreenTransitionViewModel ): DeviceEntryIconTransition diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt index 4bc2d86e6b54..a203c53be01e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt @@ -26,6 +26,7 @@ import androidx.constraintlayout.widget.ConstraintSet.BOTTOM import androidx.constraintlayout.widget.ConstraintSet.END import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID import androidx.constraintlayout.widget.ConstraintSet.START +import androidx.constraintlayout.widget.ConstraintSet.VISIBILITY_MODE_IGNORE import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT import androidx.core.view.isVisible import com.android.systemui.Flags.keyguardBottomAreaRefactor @@ -103,7 +104,8 @@ constructor( BOTTOM, resources.getDimensionPixelSize(R.dimen.keyguard_affordance_vertical_offset) ) - setVisibility(R.id.keyguard_settings_button, View.GONE) + // Ignore ConstrainSet's default visibility, and let the view choose + setVisibilityMode(R.id.keyguard_settings_button, VISIBILITY_MODE_IGNORE) } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt index b4b48a8fb932..4fd92d70fb07 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt @@ -25,7 +25,6 @@ import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flatMapLatest /** @@ -60,7 +59,7 @@ constructor( if (udfpsEnrolledAndEnabled) { transitionAnimation.immediatelyTransitionTo(1f) } else { - emptyFlow() + transitionAnimation.immediatelyTransitionTo(0f) } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModel.kt new file mode 100644 index 000000000000..9649af73eadb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModel.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor +import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest + +/** + * Breaks down ALTERNATE BOUNCER->DOZING transition into discrete steps for corresponding views to + * consume. + */ +@ExperimentalCoroutinesApi +@SysUISingleton +class AlternateBouncerToDozingTransitionViewModel +@Inject +constructor( + deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, + animationFlow: KeyguardTransitionAnimationFlow, +) : DeviceEntryIconTransition { + private val transitionAnimation = + animationFlow.setup( + duration = FromAlternateBouncerTransitionInteractor.TO_DOZING_DURATION, + from = KeyguardState.ALTERNATE_BOUNCER, + to = KeyguardState.DOZING, + ) + + val deviceEntryBackgroundViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(0f) + + override val deviceEntryParentViewAlpha: Flow<Float> = + deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolledAndEnabled + -> + if (udfpsEnrolledAndEnabled) { + transitionAnimation.immediatelyTransitionTo(1f) + } else { + transitionAnimation.immediatelyTransitionTo(0f) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt index 8a3b57ba027f..5741b9485287 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodAlphaViewModel.kt @@ -29,7 +29,6 @@ import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combineTransform -import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.onStart /** Models UI state for the alpha of the AOD (always-on display). */ @@ -46,24 +45,23 @@ constructor( /** The alpha level for the entire lockscreen while in AOD. */ val alpha: Flow<Float> = combineTransform( - keyguardTransitionInteractor.transitions, - goneToAodTransitionViewModel.enterFromTopAnimationAlpha.onStart { emit(0f) }, - goneToDozingTransitionViewModel.lockscreenAlpha.onStart { emit(0f) }, - keyguardInteractor.keyguardAlpha.onStart { emit(1f) }, - ) { step, goneToAodAlpha, goneToDozingAlpha, keyguardAlpha -> - if (step.to == GONE) { - // When transitioning to GONE, only emit a value when complete as other - // transitions may be controlling the alpha fade - if (step.value == 1f) { - emit(0f) - } - } else if (step.from == GONE && step.to == AOD) { - emit(goneToAodAlpha) - } else if (step.from == GONE && step.to == DOZING) { - emit(goneToDozingAlpha) - } else if (!migrateClocksToBlueprint()) { - emit(keyguardAlpha) + keyguardTransitionInteractor.transitions, + goneToAodTransitionViewModel.enterFromTopAnimationAlpha.onStart { emit(0f) }, + goneToDozingTransitionViewModel.lockscreenAlpha.onStart { emit(0f) }, + keyguardInteractor.keyguardAlpha.onStart { emit(1f) }, + ) { step, goneToAodAlpha, goneToDozingAlpha, keyguardAlpha -> + if (step.to == GONE) { + // When transitioning to GONE, only emit a value when complete as other + // transitions may be controlling the alpha fade + if (step.value == 1f) { + emit(0f) } + } else if (step.from == GONE && step.to == AOD) { + emit(goneToAodAlpha) + } else if (step.from == GONE && step.to == DOZING) { + emit(goneToDozingAlpha) + } else if (!migrateClocksToBlueprint()) { + emit(keyguardAlpha) } - .distinctUntilChanged() + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt index 8665aabc3ef7..7be390a4526f 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt @@ -28,10 +28,6 @@ import com.android.systemui.keyguard.domain.interactor.BurnInInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.BurnInModel -import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER -import com.android.systemui.keyguard.shared.model.KeyguardState.AOD -import com.android.systemui.keyguard.shared.model.KeyguardState.GONE -import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING import com.android.systemui.keyguard.shared.model.TransitionState.STARTED @@ -47,7 +43,6 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onStart /** @@ -127,17 +122,9 @@ constructor( params: BurnInParameters, ): Flow<BurnInModel> { return combine( - merge( - keyguardTransitionInteractor.transition(GONE, AOD).map { it.value }, - keyguardTransitionInteractor.transition(AOD, PRIMARY_BOUNCER).map { - 1f - it.value - }, - keyguardTransitionInteractor.transition(ALTERNATE_BOUNCER, AOD).map { - it.value - }, - keyguardTransitionInteractor.dozeAmountTransition.map { it.value }, - ) - .map { dozeAmount -> Interpolators.FAST_OUT_SLOW_IN.getInterpolation(dozeAmount) }, + keyguardTransitionInteractor.dozeAmountTransition.map { + Interpolators.FAST_OUT_SLOW_IN.getInterpolation(it.value) + }, burnInInteractor.keyguardBurnIn, ) { interpolated, burnIn -> val useScaleOnly = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt index 302ba7226e77..662a77ee7193 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt @@ -46,6 +46,11 @@ constructor( dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel, alternateBouncerToAodTransitionViewModel: AlternateBouncerToAodTransitionViewModel, goneToLockscreenTransitionViewModel: GoneToLockscreenTransitionViewModel, + goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel, + primaryBouncerToDozingTransitionViewModel: PrimaryBouncerToDozingTransitionViewModel, + lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel, + dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel, + alternateBouncerToDozingTransitionViewModel: AlternateBouncerToDozingTransitionViewModel, ) { val color: Flow<Int> = deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBackground -> @@ -82,6 +87,11 @@ constructor( dreamingToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha, alternateBouncerToAodTransitionViewModel.deviceEntryBackgroundViewAlpha, goneToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha, + goneToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha, + primaryBouncerToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha, + lockscreenToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha, + dozingToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha, + alternateBouncerToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha, ) .merge() } else { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt index ad6a36c71e39..62810974be80 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt @@ -33,6 +33,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart @@ -48,9 +49,9 @@ constructor( deviceEntryIconViewModel: DeviceEntryIconViewModel, udfpsOverlayInteractor: UdfpsOverlayInteractor, ) { - private val isShowingAod: Flow<Boolean> = + private val isShowingAodOrDozing: Flow<Boolean> = transitionInteractor.startedKeyguardState.map { keyguardState -> - keyguardState == KeyguardState.AOD + keyguardState == KeyguardState.AOD || keyguardState == KeyguardState.DOZING } private fun getColor(usingBackgroundProtection: Boolean): Int { @@ -68,13 +69,15 @@ constructor( .onStart { emit(getColor(useBgProtection)) } } + // While dozing, the display can show the AOD UI; show the AOD udfps when dozing private val useAodIconVariant: Flow<Boolean> = - combine(isShowingAod, deviceEntryUdfpsInteractor.isUdfpsSupported) { - isTransitionToAod, - isUdfps -> - isTransitionToAod && isUdfps + deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfspEnrolled -> + if (udfspEnrolled) { + isShowingAodOrDozing.distinctUntilChanged() + } else { + flowOf(false) } - .distinctUntilChanged() + } private val padding: Flow<Int> = deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { udfpsSupported -> diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt index c9cf0c31a8fd..31e809356e02 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt @@ -37,6 +37,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf @@ -206,6 +207,7 @@ constructor( DeviceEntryIconView.IconType.LOCK } } + val isVisible: Flow<Boolean> = deviceEntryViewAlpha.map { it > 0f }.distinctUntilChanged() val isLongPressEnabled: Flow<Boolean> = combine( iconType, @@ -217,6 +219,7 @@ constructor( DeviceEntryIconView.IconType.FINGERPRINT -> false } } + val accessibilityDelegateHint: Flow<DeviceEntryIconView.AccessibilityHintType> = combine(iconType, isLongPressEnabled) { deviceEntryStatus, longPressEnabled -> if (longPressEnabled) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt new file mode 100644 index 000000000000..fca1604946e1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.FromDozingTransitionInteractor.Companion.TO_GONE_DURATION +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow + +/** Breaks down DOZING->GONE transition into discrete steps for corresponding views to consume. */ +@ExperimentalCoroutinesApi +@SysUISingleton +class DozingToGoneTransitionViewModel +@Inject +constructor( + animationFlow: KeyguardTransitionAnimationFlow, +) : DeviceEntryIconTransition { + + private val transitionAnimation = + animationFlow.setup( + duration = TO_GONE_DURATION, + from = KeyguardState.DOZING, + to = KeyguardState.GONE, + ) + + override val deviceEntryParentViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(0f) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt index f81941bf064b..168d6e16daa2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt @@ -52,6 +52,9 @@ constructor( val lockscreenAlpha: Flow<Float> = shortcutsAlpha + val deviceEntryBackgroundViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(1f) + override val deviceEntryParentViewAlpha: Flow<Float> = transitionAnimation.immediatelyTransitionTo(1f) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModel.kt new file mode 100644 index 000000000000..4395c3436a71 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModel.kt @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.FromDozingTransitionInteractor.Companion.TO_PRIMARY_BOUNCER_DURATION +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow + +/** + * Breaks down DOZING->PRIMARY BOUNCER transition into discrete steps for corresponding views to + * consume. + */ +@ExperimentalCoroutinesApi +@SysUISingleton +class DozingToPrimaryBouncerTransitionViewModel +@Inject +constructor( + animationFlow: KeyguardTransitionAnimationFlow, +) : DeviceEntryIconTransition { + + private val transitionAnimation = + animationFlow.setup( + duration = TO_PRIMARY_BOUNCER_DURATION, + from = KeyguardState.DOZING, + to = KeyguardState.PRIMARY_BOUNCER, + ) + + override val deviceEntryParentViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(0f) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt index 374a93275ff2..c64f277b519a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt @@ -17,18 +17,26 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.app.animation.Interpolators.EMPHASIZED +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.res.R import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest +@OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class DreamingToGlanceableHubTransitionViewModel @Inject -constructor(animationFlow: KeyguardTransitionAnimationFlow) { +constructor( + animationFlow: KeyguardTransitionAnimationFlow, + configurationInteractor: ConfigurationInteractor, +) { private val transitionAnimation = animationFlow.setup( @@ -37,14 +45,18 @@ constructor(animationFlow: KeyguardTransitionAnimationFlow) { to = KeyguardState.GLANCEABLE_HUB, ) - fun dreamOverlayTranslationX(translatePx: Int): Flow<Float> { - return transitionAnimation.sharedFlow( - duration = TO_GLANCEABLE_HUB_DURATION, - onStep = { it * -translatePx }, - interpolator = EMPHASIZED, - name = "DREAMING->GLANCEABLE_HUB: overlayTranslationX", - ) - } + val dreamOverlayTranslationX: Flow<Float> = + configurationInteractor + .dimensionPixelSize(R.dimen.dreaming_to_hub_transition_dream_overlay_translation_x) + .flatMapLatest { translatePx -> + transitionAnimation.sharedFlow( + duration = TO_GLANCEABLE_HUB_DURATION, + onStep = { value -> value * translatePx }, + interpolator = EMPHASIZED, + onCancel = { 0f }, + name = "DREAMING->GLANCEABLE_HUB: overlayTranslationX", + ) + } val dreamOverlayAlpha: Flow<Float> = transitionAnimation.sharedFlow( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt index 3802d5de5811..d3277cd295ac 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt @@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.app.animation.Interpolators.EMPHASIZED import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor @@ -43,7 +42,6 @@ class DreamingToLockscreenTransitionViewModel constructor( keyguardTransitionInteractor: KeyguardTransitionInteractor, private val fromDreamingTransitionInteractor: FromDreamingTransitionInteractor, - private val deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, animationFlow: KeyguardTransitionAnimationFlow, ) : DeviceEntryIconTransition { fun startTransition() = fromDreamingTransitionInteractor.startToLockscreenTransition() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt new file mode 100644 index 000000000000..478c4faa1be3 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.app.animation.Interpolators +import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.res.R +import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest + +@OptIn(ExperimentalCoroutinesApi::class) +@SysUISingleton +class GlanceableHubToDreamingTransitionViewModel +@Inject +constructor( + animationFlow: KeyguardTransitionAnimationFlow, + configurationInteractor: ConfigurationInteractor, +) { + + private val transitionAnimation = + animationFlow.setup( + duration = FROM_GLANCEABLE_HUB_DURATION, + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.DREAMING, + ) + + val dreamOverlayAlpha: Flow<Float> = + transitionAnimation.sharedFlow( + duration = 167.milliseconds, + startTime = 167.milliseconds, + onStep = { it }, + name = "GLANCEABLE_HUB->DREAMING: dreamOverlayAlpha", + ) + + val dreamOverlayTranslationX: Flow<Float> = + configurationInteractor + .dimensionPixelSize(R.dimen.hub_to_dreaming_transition_dream_overlay_translation_x) + .flatMapLatest { translatePx: Int -> + transitionAnimation.sharedFlow( + duration = FROM_GLANCEABLE_HUB_DURATION, + onStep = { value -> -translatePx + value * translatePx }, + interpolator = Interpolators.EMPHASIZED, + onCancel = { -translatePx.toFloat() }, + name = "GLANCEABLE_HUB->LOCKSCREEN: dreamOverlayTranslationX" + ) + } + + private companion object { + val FROM_GLANCEABLE_HUB_DURATION = 1.seconds + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt index 55a289ef890f..80a6bda65b99 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt @@ -17,13 +17,17 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DOZING_DURATION import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flatMapLatest /** Breaks down GONE->DOZING transition into discrete steps for corresponding views to consume. */ @ExperimentalCoroutinesApi @@ -31,8 +35,9 @@ import kotlinx.coroutines.flow.Flow class GoneToDozingTransitionViewModel @Inject constructor( + deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, animationFlow: KeyguardTransitionAnimationFlow, -) { +) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( @@ -48,4 +53,17 @@ constructor( onCancel = { 1f }, onFinish = { 1f }, ) + + val deviceEntryBackgroundViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(0f) + + override val deviceEntryParentViewAlpha: Flow<Float> = + deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { + isUdfpsEnrolledAndEnabled -> + if (isUdfpsEnrolledAndEnabled) { + transitionAnimation.immediatelyTransitionTo(1f) + } else { + emptyFlow() + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt index 921eb66cd3cc..bdcaf0951c5b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt @@ -74,6 +74,10 @@ constructor( private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel, private val glanceableHubToLockscreenTransitionViewModel: GlanceableHubToLockscreenTransitionViewModel, + private val goneToAodTransitionViewModel: GoneToAodTransitionViewModel, + private val goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel, + private val lockscreenToAodTransitionViewModel: LockscreenToAodTransitionViewModel, + private val lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel, private val lockscreenToDreamingTransitionViewModel: LockscreenToDreamingTransitionViewModel, private val lockscreenToGlanceableHubTransitionViewModel: LockscreenToGlanceableHubTransitionViewModel, @@ -133,17 +137,24 @@ constructor( fun alpha(viewState: ViewStateAccessor): Flow<Float> { return combine( communalInteractor.isIdleOnCommunal, - keyguardTransitionInteractor.transitionValue(GONE).onStart { emit(0f) }, + keyguardTransitionInteractor + .transitionValue(GONE) + .map { it == 1f } + .onStart { emit(false) } + .distinctUntilChanged(), // The transitions are mutually exclusive, so they are safe to merge to get the last // value emitted by any of them. Do not add flows that cannot make this guarantee. merge( - aodAlphaViewModel.alpha, alphaOnShadeExpansion, keyguardInteractor.dismissAlpha.filterNotNull(), alternateBouncerToGoneTransitionViewModel.lockscreenAlpha, aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState), dozingToLockscreenTransitionViewModel.lockscreenAlpha, glanceableHubToLockscreenTransitionViewModel.keyguardAlpha, + goneToAodTransitionViewModel.enterFromTopAnimationAlpha, + goneToDozingTransitionViewModel.lockscreenAlpha, + lockscreenToAodTransitionViewModel.lockscreenAlpha(viewState), + lockscreenToDozingTransitionViewModel.lockscreenAlpha, lockscreenToDreamingTransitionViewModel.lockscreenAlpha, lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha, lockscreenToGoneTransitionViewModel.lockscreenAlpha(viewState), @@ -156,8 +167,8 @@ constructor( primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha, ) .onStart { emit(1f) } - ) { isIdleOnCommunal, goneValue, alpha -> - if (isIdleOnCommunal || goneValue == 1f) { + ) { isIdleOnCommunal, gone, alpha -> + if (isIdleOnCommunal || gone) { // Keyguard should not show while the communal hub is fully visible. This check // is added since at the moment, closing the notification shade will cause the // keyguard alpha to be set back to 1. Also ensure keyguard is never visible diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt index 7bf51a7d3d54..1f9f3043dfdf 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToAodTransitionViewModel.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.ui.viewmodel +import android.util.MathUtils import com.android.systemui.dagger.SysUISingleton import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor @@ -67,6 +68,15 @@ constructor( onCancel = { 1f }, ) + fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> { + var startAlpha = 1f + return transitionAnimation.sharedFlow( + duration = 500.milliseconds, + onStart = { startAlpha = viewState.alpha() }, + onStep = { MathUtils.lerp(startAlpha, 1f, it) }, + ) + } + override val deviceEntryParentViewAlpha: Flow<Float> = deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { isUdfpsEnrolledAndEnabled -> diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt index 4c0cd2f58eb7..c836f01e2ee9 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt @@ -17,19 +17,25 @@ package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DOZING_DURATION import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest +@OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class LockscreenToDozingTransitionViewModel @Inject constructor( + deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, animationFlow: KeyguardTransitionAnimationFlow, -) { +) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( @@ -38,6 +44,14 @@ constructor( to = KeyguardState.DOZING, ) + val lockscreenAlpha: Flow<Float> = + transitionAnimation.sharedFlow( + duration = 250.milliseconds, + onStep = { 1 - it }, + onFinish = { 1f }, + onCancel = { 1f }, + ) + val shortcutsAlpha: Flow<Float> = transitionAnimation.sharedFlow( duration = 250.milliseconds, @@ -45,4 +59,19 @@ constructor( onFinish = { 0f }, onCancel = { 1f }, ) + + val deviceEntryBackgroundViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(0f) + + override val deviceEntryParentViewAlpha: Flow<Float> = + deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { + isUdfpsEnrolledAndEnabled -> + transitionAnimation.immediatelyTransitionTo( + if (isUdfpsEnrolledAndEnabled) { + 1f + } else { + 0f + } + ) + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModel.kt new file mode 100644 index 000000000000..13f651a9ff5d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModel.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor +import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_DOZING_DURATION +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flatMapLatest + +/** + * Breaks down PRIMARY BOUNCER->DOZING transition into discrete steps for corresponding views to + * consume. + */ +@ExperimentalCoroutinesApi +@SysUISingleton +class PrimaryBouncerToDozingTransitionViewModel +@Inject +constructor( + deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, + animationFlow: KeyguardTransitionAnimationFlow, +) : DeviceEntryIconTransition { + + private val transitionAnimation = + animationFlow.setup( + duration = TO_DOZING_DURATION, + from = KeyguardState.PRIMARY_BOUNCER, + to = KeyguardState.DOZING, + ) + + val deviceEntryBackgroundViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(0f) + + override val deviceEntryParentViewAlpha: Flow<Float> = + deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { + isUdfpsEnrolledAndEnabled -> + if (isUdfpsEnrolledAndEnabled) { + transitionAnimation.immediatelyTransitionTo(1f) + } else { + emptyFlow() + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt index 378ce52b4331..53f448826e80 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToGoneTransitionViewModel.kt @@ -60,6 +60,22 @@ constructor( private var leaveShadeOpen: Boolean = false private var willRunDismissFromKeyguard: Boolean = false + val notificationAlpha: Flow<Float> = + transitionAnimation.sharedFlow( + duration = 200.milliseconds, + onStart = { + leaveShadeOpen = statusBarStateController.leaveOpenOnKeyguardHide() + willRunDismissFromKeyguard = primaryBouncerInteractor.willRunDismissFromKeyguard() + }, + onStep = { + if (willRunDismissFromKeyguard || leaveShadeOpen) { + 1f + } else { + 1f - it + } + }, + ) + /** Bouncer container alpha */ val bouncerAlpha: Flow<Float> = if (featureFlags.isEnabled(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT)) { @@ -94,6 +110,7 @@ constructor( } else { createLockscreenAlpha(primaryBouncerInteractor::willRunDismissFromKeyguard) } + private fun createLockscreenAlpha(willRunAnimationOnKeyguard: () -> Boolean): Flow<Float> { return transitionAnimation.sharedFlow( duration = 50.milliseconds, diff --git a/packages/SystemUI/src/com/android/systemui/media/OWNERS b/packages/SystemUI/src/com/android/systemui/media/OWNERS index 69ea57bfd397..5eb14fc40327 100644 --- a/packages/SystemUI/src/com/android/systemui/media/OWNERS +++ b/packages/SystemUI/src/com/android/systemui/media/OWNERS @@ -1 +1,9 @@ -per-file MediaProjectionPermissionActivity.java = michaelwr@google.com +# Bug component: 78010 + +asc@google.com +ethibodeau@google.com +michaelmikhil@google.com + +# Audio team +per-file RingtonePlayer.java = file:/services/core/java/com/android/server/audio/OWNERS +per-file NotificationPlayer.java = file:/services/core/java/com/android/server/audio/OWNERS diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt index 6fc22ea60a9e..865c49e1d817 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt @@ -17,6 +17,7 @@ package com.android.systemui.media.controls.domain.pipeline import android.annotation.SuppressLint +import android.app.ActivityOptions import android.app.BroadcastOptions import android.app.Notification import android.app.Notification.EXTRA_SUBSTITUTE_APP_NAME @@ -1272,7 +1273,7 @@ class MediaDataManager( val options = BroadcastOptions.makeBasic() options.setInteractive(true) options.setPendingIntentBackgroundActivityStartMode( - BroadcastOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED ) intent.send(options.toBundle()) true diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java index 4e940f1f84da..840b309aee39 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java @@ -18,7 +18,7 @@ package com.android.systemui.media.controls.ui.controller; import static android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS; -import static com.android.systemui.Flags.legacyLeAudioSharing; +import static com.android.settingslib.flags.Flags.legacyLeAudioSharing; import static com.android.systemui.media.controls.shared.model.SmartspaceMediaDataKt.NUM_REQUIRED_RECOMMENDATIONS; import android.animation.Animator; diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java index 8e0191ec330f..1e317554859c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java @@ -16,6 +16,8 @@ package com.android.systemui.media.dialog; +import static com.android.settingslib.flags.Flags.legacyLeAudioSharing; + import android.app.AlertDialog; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothLeBroadcastAssistant; @@ -492,6 +494,7 @@ public class MediaOutputBroadcastDialog extends MediaOutputBaseDialog { @Override public boolean isBroadcastSupported() { + if (!legacyLeAudioSharing()) return false; boolean isBluetoothLeDevice = false; if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) { isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice( diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java index c379d0e68e76..eb6a32023eb7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java @@ -16,7 +16,7 @@ package com.android.systemui.media.dialog; -import static com.android.systemui.Flags.legacyLeAudioSharing; +import static com.android.settingslib.flags.Flags.legacyLeAudioSharing; import android.content.Context; import android.os.Bundle; diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt index 1002cc3bd3bb..38d31ed92141 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt @@ -16,6 +16,7 @@ package com.android.systemui.media.dialog +import com.android.settingslib.flags.Flags.legacyLeAudioSharing import android.content.BroadcastReceiver import android.content.Context import android.content.Intent @@ -44,6 +45,7 @@ class MediaOutputDialogReceiver @Inject constructor( mediaOutputDialogFactory.createDialogForSystemRouting() } MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG -> { + if (!legacyLeAudioSharing()) return val packageName: String? = intent.getStringExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME) launchMediaOutputBroadcastDialogIfPossible(packageName) diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS b/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS new file mode 100644 index 000000000000..95b8fa74feeb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 1280508 + +# Files in this directory should still be reviewed by a member of SystemUI team diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt index afe628527833..f1cade7512e2 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt @@ -16,9 +16,6 @@ package com.android.systemui.mediaprojection -import android.compat.annotation.ChangeId -import android.compat.annotation.Disabled -import android.compat.annotation.Overridable import android.content.Context import android.media.projection.IMediaProjection import android.media.projection.IMediaProjectionManager @@ -34,18 +31,6 @@ import android.util.Log */ class MediaProjectionServiceHelper { companion object { - /** - * This change id ensures that users are presented with a choice of capturing a single app - * or the entire screen when initiating a MediaProjection session, overriding the usage of - * MediaProjectionConfig#createConfigForDefaultDisplay. - * - * @hide - */ - @ChangeId - @Overridable - @Disabled - const val OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION = 316897322L // buganizer id - private const val TAG = "MediaProjectionServiceHelper" private val service = IMediaProjectionManager.Stub.asInterface( diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/OWNERS b/packages/SystemUI/src/com/android/systemui/mediaprojection/OWNERS new file mode 100644 index 000000000000..bd7407729774 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/OWNERS @@ -0,0 +1,5 @@ +# Bug component: 1345447 + +include /media/java/android/media/projection/OWNERS +chrisgollner@google.com +nickchameyev@google.com diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt index a811065fdc65..e1741c73d453 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt @@ -18,7 +18,7 @@ package com.android.systemui.mediaprojection.appselector.view import android.app.ActivityOptions import android.app.ActivityOptions.LaunchCookie -import android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED +import android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED import android.app.IActivityTaskManager import android.graphics.Rect import android.view.LayoutInflater diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java index 0769731bffb1..8b034b293dcb 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java @@ -16,26 +16,21 @@ package com.android.systemui.mediaprojection.permission; -import static android.Manifest.permission.LOG_COMPAT_CHANGE; -import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG; import static android.media.projection.IMediaProjectionManager.EXTRA_PACKAGE_REUSING_GRANTED_CONSENT; import static android.media.projection.IMediaProjectionManager.EXTRA_USER_REVIEW_GRANTED_CONSENT; import static android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL; import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_DISPLAY; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; -import static com.android.systemui.mediaprojection.MediaProjectionServiceHelper.OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION; import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.ENTIRE_SCREEN; import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.SINGLE_APP; import android.annotation.Nullable; -import android.annotation.RequiresPermission; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityOptions.LaunchCookie; import android.app.AlertDialog; import android.app.StatusBarManager; -import android.app.compat.CompatChanges; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -109,7 +104,6 @@ public class MediaProjectionPermissionActivity extends Activity } @Override - @RequiresPermission(allOf = {READ_COMPAT_CHANGE_CONFIG, LOG_COMPAT_CHANGE}) public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -237,9 +231,6 @@ public class MediaProjectionPermissionActivity extends Activity // the correct screen width when in split screen. Context dialogContext = getApplicationContext(); if (isPartialScreenSharingEnabled()) { - final boolean overrideDisableSingleAppOption = CompatChanges.isChangeEnabled( - OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION, - mPackageName, getHostUserHandle()); MediaProjectionPermissionDialogDelegate delegate = new MediaProjectionPermissionDialogDelegate( dialogContext, @@ -251,7 +242,6 @@ public class MediaProjectionPermissionActivity extends Activity }, () -> finish(RECORD_CANCEL, /* projection= */ null), appName, - overrideDisableSingleAppOption, mUid, mMediaProjectionMetricsLogger); mDialog = diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt index 9ce8070131fa..0f54e934f3cf 100644 --- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt @@ -30,12 +30,11 @@ class MediaProjectionPermissionDialogDelegate( private val onStartRecordingClicked: Consumer<MediaProjectionPermissionDialogDelegate>, private val onCancelClicked: Runnable, private val appName: String?, - forceShowPartialScreenshare: Boolean, hostUid: Int, mediaProjectionMetricsLogger: MediaProjectionMetricsLogger, ) : BaseMediaProjectionPermissionDialogDelegate<AlertDialog>( - createOptionList(context, appName, mediaProjectionConfig, forceShowPartialScreenshare), + createOptionList(context, appName, mediaProjectionConfig), appName, hostUid, mediaProjectionMetricsLogger @@ -66,8 +65,7 @@ class MediaProjectionPermissionDialogDelegate( private fun createOptionList( context: Context, appName: String?, - mediaProjectionConfig: MediaProjectionConfig?, - overrideDisableSingleAppOption: Boolean = false, + mediaProjectionConfig: MediaProjectionConfig? ): List<ScreenShareOption> { val singleAppWarningText = if (appName == null) { @@ -82,13 +80,8 @@ class MediaProjectionPermissionDialogDelegate( R.string.media_projection_entry_app_permission_dialog_warning_entire_screen } - // The single app option should only be disabled if there is an app name provided, - // the client has setup a MediaProjection with - // MediaProjectionConfig#createConfigForDefaultDisplay, AND it hasn't been overridden by - // the OVERRIDE_DISABLE_SINGLE_APP_OPTION per-app override. val singleAppOptionDisabled = appName != null && - !overrideDisableSingleAppOption && mediaProjectionConfig?.regionToCapture == MediaProjectionConfig.CAPTURE_REGION_FIXED_DISPLAY diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java index aa03e6e00859..5dd1bd80140b 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java @@ -495,10 +495,6 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, return mBehavior != BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; } - private boolean isImmersiveMode() { - return mBehavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; - } - public void onConfigurationChanged(Configuration configuration) { mEdgeBackGestureHandler.onConfigurationChanged(configuration); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt index 6b53c7ac0a14..7ece6e0defc1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegate.kt @@ -37,11 +37,13 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.android.internal.logging.UiEventLogger -import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.res.R import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.time.SystemClock +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow @@ -52,19 +54,24 @@ import kotlinx.coroutines.isActive import kotlinx.coroutines.withContext /** Dialog for showing active, connected and saved bluetooth devices. */ -@SysUISingleton -internal class BluetoothTileDialog -constructor( - private val bluetoothToggleInitialValue: Boolean, - private val initialUiProperties: BluetoothTileDialogViewModel.UiProperties, - private val cachedContentHeight: Int, - private val bluetoothTileDialogCallback: BluetoothTileDialogCallback, +class BluetoothTileDialogDelegate +@AssistedInject +internal constructor( + @Assisted private val context: Context, + @Assisted private val initialUiProperties: BluetoothTileDialogViewModel.UiProperties, + @Assisted private val cachedContentHeight: Int, + @Assisted private val bluetoothToggleInitialValue: Boolean, + @Assisted private val bluetoothTileDialogCallback: BluetoothTileDialogCallback, + @Assisted private val dismissListener: Runnable, @Main private val mainDispatcher: CoroutineDispatcher, private val systemClock: SystemClock, private val uiEventLogger: UiEventLogger, private val logger: BluetoothTileDialogLogger, - context: Context, -) : SystemUIDialog(context, DEFAULT_THEME, DEFAULT_DISMISS_ON_DEVICE_LOCK) { + private val systemuiDialogFactory: SystemUIDialog.Factory, + mainLayoutInflater: LayoutInflater, +) : SystemUIDialog.Delegate { + + private val layoutInflater = mainLayoutInflater.cloneInContext(context) private val mutableBluetoothStateToggle: MutableStateFlow<Boolean> = MutableStateFlow(bluetoothToggleInitialValue) @@ -91,78 +98,72 @@ constructor( private var lastItemRow: Int = -1 - private lateinit var toggleView: Switch - private lateinit var subtitleTextView: TextView - private lateinit var autoOnToggle: Switch - private lateinit var autoOnToggleView: View - private lateinit var doneButton: View - private lateinit var seeAllButton: View - private lateinit var pairNewDeviceButton: View - private lateinit var deviceListView: RecyclerView - private lateinit var scrollViewContent: View - private lateinit var progressBarAnimation: ProgressBar - private lateinit var progressBarBackground: View - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) + @AssistedFactory + internal interface Factory { + fun create( + context: Context, + initialUiProperties: BluetoothTileDialogViewModel.UiProperties, + cachedContentHeight: Int, + bluetoothEnabled: Boolean, + dialogCallback: BluetoothTileDialogCallback, + dimissListener: Runnable + ): BluetoothTileDialogDelegate + } + + override fun createDialog(): SystemUIDialog { + val dialog = systemuiDialogFactory.create(this, context) + + return dialog + } + + override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) { + SystemUIDialog.registerDismissListener(dialog, dismissListener) uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TILE_DIALOG_SHOWN) - LayoutInflater.from(context).inflate(R.layout.bluetooth_tile_dialog, null).apply { + layoutInflater.inflate(R.layout.bluetooth_tile_dialog, null).apply { accessibilityPaneTitle = context.getText(R.string.accessibility_desc_quick_settings) - setContentView(this) + dialog.setContentView(this) } - toggleView = requireViewById(R.id.bluetooth_toggle) - subtitleTextView = requireViewById(R.id.bluetooth_tile_dialog_subtitle) as TextView - autoOnToggle = requireViewById(R.id.bluetooth_auto_on_toggle) - autoOnToggleView = requireViewById(R.id.bluetooth_auto_on_toggle_layout) - doneButton = requireViewById(R.id.done_button) - seeAllButton = requireViewById(R.id.see_all_button) - pairNewDeviceButton = requireViewById(R.id.pair_new_device_button) - deviceListView = requireViewById<RecyclerView>(R.id.device_list) - - setupToggle() - setupRecyclerView() - - subtitleTextView.text = context.getString(initialUiProperties.subTitleResId) - doneButton.setOnClickListener { dismiss() } - seeAllButton.setOnClickListener { bluetoothTileDialogCallback.onSeeAllClicked(it) } - pairNewDeviceButton.setOnClickListener { + setupToggle(dialog) + setupRecyclerView(dialog) + + getSubtitleTextView(dialog).text = context.getString(initialUiProperties.subTitleResId) + dialog.requireViewById<View>(R.id.done_button).setOnClickListener { dialog.dismiss() } + getSeeAllButton(dialog).setOnClickListener { + bluetoothTileDialogCallback.onSeeAllClicked(it) + } + getPairNewDeviceButton(dialog).setOnClickListener { bluetoothTileDialogCallback.onPairNewDeviceClicked(it) } - requireViewById<View>(R.id.scroll_view).apply { - scrollViewContent = this + getScrollViewContent(dialog).apply { minimumHeight = resources.getDimensionPixelSize(initialUiProperties.scrollViewMinHeightResId) layoutParams.height = maxOf(cachedContentHeight, minimumHeight) } - progressBarAnimation = requireViewById(R.id.bluetooth_tile_dialog_progress_animation) - progressBarBackground = requireViewById(R.id.bluetooth_tile_dialog_progress_background) } - override fun start() { + override fun onStart(dialog: SystemUIDialog) { lastUiUpdateMs = systemClock.elapsedRealtime() } - override fun dismiss() { - if (::scrollViewContent.isInitialized) { - mutableContentHeight.tryEmit(scrollViewContent.measuredHeight) - } - super.dismiss() + override fun onStop(dialog: SystemUIDialog) { + mutableContentHeight.tryEmit(getScrollViewContent(dialog).measuredHeight) } - internal suspend fun animateProgressBar(animate: Boolean) { + internal suspend fun animateProgressBar(dialog: SystemUIDialog, animate: Boolean) { withContext(mainDispatcher) { if (animate) { - showProgressBar() + showProgressBar(dialog) } else { delay(PROGRESS_BAR_ANIMATION_DURATION_MS) - hideProgressBar() + hideProgressBar(dialog) } } } internal suspend fun onDeviceItemUpdated( + dialog: SystemUIDialog, deviceItem: List<DeviceItem>, showSeeAll: Boolean, showPairNewDevice: Boolean @@ -176,10 +177,11 @@ constructor( } if (isActive) { deviceItemAdapter.refreshDeviceItemList(deviceItem) { - seeAllButton.visibility = if (showSeeAll) VISIBLE else GONE - pairNewDeviceButton.visibility = if (showPairNewDevice) VISIBLE else GONE + getSeeAllButton(dialog).visibility = if (showSeeAll) VISIBLE else GONE + getPairNewDeviceButton(dialog).visibility = + if (showPairNewDevice) VISIBLE else GONE // Update the height after data is updated - scrollViewContent.layoutParams.height = WRAP_CONTENT + getScrollViewContent(dialog).layoutParams.height = WRAP_CONTENT lastUiUpdateMs = systemClock.elapsedRealtime() lastItemRow = itemRow logger.logDeviceUiUpdate(lastUiUpdateMs - start) @@ -189,29 +191,29 @@ constructor( } internal fun onBluetoothStateUpdated( + dialog: SystemUIDialog, isEnabled: Boolean, uiProperties: BluetoothTileDialogViewModel.UiProperties ) { - toggleView.apply { + getToggleView(dialog).apply { isChecked = isEnabled setEnabled(true) alpha = ENABLED_ALPHA } - subtitleTextView.text = context.getString(uiProperties.subTitleResId) - autoOnToggleView.visibility = uiProperties.autoOnToggleVisibility + getSubtitleTextView(dialog).text = context.getString(uiProperties.subTitleResId) + getAutoOnToggleView(dialog).visibility = uiProperties.autoOnToggleVisibility } - internal fun onBluetoothAutoOnUpdated(isEnabled: Boolean) { - if (::autoOnToggle.isInitialized) { - autoOnToggle.apply { - isChecked = isEnabled - setEnabled(true) - alpha = ENABLED_ALPHA - } + internal fun onBluetoothAutoOnUpdated(dialog: SystemUIDialog, isEnabled: Boolean) { + getAutoOnToggle(dialog).apply { + isChecked = isEnabled + setEnabled(true) + alpha = ENABLED_ALPHA } } - private fun setupToggle() { + private fun setupToggle(dialog: SystemUIDialog) { + val toggleView = getToggleView(dialog) toggleView.isChecked = bluetoothToggleInitialValue toggleView.setOnCheckedChangeListener { view, isChecked -> mutableBluetoothStateToggle.value = isChecked @@ -223,8 +225,8 @@ constructor( uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_TOGGLE_CLICKED) } - autoOnToggleView.visibility = initialUiProperties.autoOnToggleVisibility - autoOnToggle.setOnCheckedChangeListener { view, isChecked -> + getAutoOnToggleView(dialog).visibility = initialUiProperties.autoOnToggleVisibility + getAutoOnToggle(dialog).setOnCheckedChangeListener { view, isChecked -> mutableBluetoothAutoOnToggle.value = isChecked view.apply { isEnabled = false @@ -234,30 +236,66 @@ constructor( } } - private fun setupRecyclerView() { - deviceListView.apply { + private fun getToggleView(dialog: SystemUIDialog): Switch { + return dialog.requireViewById(R.id.bluetooth_toggle) + } + + private fun getSubtitleTextView(dialog: SystemUIDialog): TextView { + return dialog.requireViewById(R.id.bluetooth_tile_dialog_subtitle) + } + + private fun getSeeAllButton(dialog: SystemUIDialog): View { + return dialog.requireViewById(R.id.see_all_button) + } + + private fun getPairNewDeviceButton(dialog: SystemUIDialog): View { + return dialog.requireViewById(R.id.pair_new_device_button) + } + + private fun getDeviceListView(dialog: SystemUIDialog): RecyclerView { + return dialog.requireViewById(R.id.device_list) + } + + private fun getAutoOnToggle(dialog: SystemUIDialog): Switch { + return dialog.requireViewById(R.id.bluetooth_auto_on_toggle) + } + + private fun getAutoOnToggleView(dialog: SystemUIDialog): View { + return dialog.requireViewById(R.id.bluetooth_auto_on_toggle_layout) + } + + private fun getProgressBarAnimation(dialog: SystemUIDialog): ProgressBar { + return dialog.requireViewById(R.id.bluetooth_tile_dialog_progress_animation) + } + + private fun getProgressBarBackground(dialog: SystemUIDialog): View { + return dialog.requireViewById(R.id.bluetooth_tile_dialog_progress_animation) + } + + private fun getScrollViewContent(dialog: SystemUIDialog): View { + return dialog.requireViewById(R.id.scroll_view) + } + + private fun setupRecyclerView(dialog: SystemUIDialog) { + getDeviceListView(dialog).apply { layoutManager = LinearLayoutManager(context) adapter = deviceItemAdapter } } - private fun showProgressBar() { - if ( - ::progressBarAnimation.isInitialized && - ::progressBarBackground.isInitialized && - progressBarAnimation.visibility != VISIBLE - ) { + private fun showProgressBar(dialog: SystemUIDialog) { + val progressBarAnimation = getProgressBarAnimation(dialog) + val progressBarBackground = getProgressBarBackground(dialog) + if (progressBarAnimation.visibility != VISIBLE) { progressBarAnimation.visibility = VISIBLE progressBarBackground.visibility = INVISIBLE } } - private fun hideProgressBar() { - if ( - ::progressBarAnimation.isInitialized && - ::progressBarBackground.isInitialized && - progressBarAnimation.visibility != INVISIBLE - ) { + private fun hideProgressBar(dialog: SystemUIDialog) { + val progressBarAnimation = getProgressBarAnimation(dialog) + val progressBarBackground = getProgressBarBackground(dialog) + if (progressBarAnimation.visibility != INVISIBLE) { progressBarAnimation.visibility = INVISIBLE progressBarBackground.visibility = VISIBLE } @@ -295,9 +333,7 @@ constructor( private val asyncListDiffer = AsyncListDiffer(this, diffUtilCallback) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DeviceItemViewHolder { - val view = - LayoutInflater.from(parent.context) - .inflate(R.layout.bluetooth_device_item, parent, false) + val view = layoutInflater.inflate(R.layout.bluetooth_device_item, parent, false) return DeviceItemViewHolder(view) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt index 5a14e5f11d38..04862077969d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt @@ -38,13 +38,11 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.ACTION_BLUETOOTH_DEVICE_DETAILS -import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.ACTION_PAIR_NEW_DEVICE -import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.ACTION_PREVIOUSLY_CONNECTED_DEVICE -import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.MAX_DEVICE_ITEM_ENTRY +import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogDelegate.Companion.ACTION_BLUETOOTH_DEVICE_DETAILS +import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogDelegate.Companion.ACTION_PAIR_NEW_DEVICE +import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogDelegate.Companion.ACTION_PREVIOUSLY_CONNECTED_DEVICE +import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogDelegate.Companion.MAX_DEVICE_ITEM_ENTRY import com.android.systemui.res.R -import com.android.systemui.statusbar.phone.SystemUIDialog -import com.android.systemui.util.time.SystemClock import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope @@ -67,13 +65,12 @@ constructor( private val bluetoothAutoOnInteractor: BluetoothAutoOnInteractor, private val dialogTransitionAnimator: DialogTransitionAnimator, private val activityStarter: ActivityStarter, - private val systemClock: SystemClock, private val uiEventLogger: UiEventLogger, - private val logger: BluetoothTileDialogLogger, @Application private val coroutineScope: CoroutineScope, @Main private val mainDispatcher: CoroutineDispatcher, @Background private val backgroundDispatcher: CoroutineDispatcher, @Main private val sharedPreferences: SharedPreferences, + private val bluetoothDialogDelegateFactory: BluetoothTileDialogDelegate.Factory, ) : BluetoothTileDialogCallback { private var job: Job? = null @@ -92,7 +89,8 @@ constructor( coroutineScope.launch(mainDispatcher) { var updateDeviceItemJob: Job? var updateDialogUiJob: Job? = null - val dialog = createBluetoothTileDialog(context) + val dialogDelegate = createBluetoothTileDialog(context) + val dialog = dialogDelegate.createDialog() view?.let { dialogTransitionAnimator.showFromView( @@ -118,13 +116,14 @@ constructor( .onEach { updateDialogUiJob?.cancel() updateDialogUiJob = launch { - dialog.apply { + dialogDelegate.apply { onDeviceItemUpdated( + dialog, it.take(MAX_DEVICE_ITEM_ENTRY), showSeeAll = it.size > MAX_DEVICE_ITEM_ENTRY, showPairNewDevice = bluetoothStateInteractor.isBluetoothEnabled ) - animateProgressBar(false) + animateProgressBar(dialog, false) } } } @@ -134,7 +133,7 @@ constructor( // the device item list and animiate the progress bar. deviceItemInteractor.deviceItemUpdateRequest .onEach { - dialog.animateProgressBar(true) + dialogDelegate.animateProgressBar(dialog, true) updateDeviceItemJob?.cancel() updateDeviceItemJob = launch { deviceItemInteractor.updateDeviceItems( @@ -150,7 +149,8 @@ constructor( bluetoothStateInteractor.bluetoothStateUpdate .filterNotNull() .onEach { - dialog.onBluetoothStateUpdated( + dialogDelegate.onBluetoothStateUpdated( + dialog, it, UiProperties.build(it, isAutoOnToggleFeatureAvailable()) ) @@ -166,20 +166,20 @@ constructor( // bluetoothStateToggle is emitted when user toggles the bluetooth state switch, // send the new value to the bluetoothStateInteractor and animate the progress bar. - dialog.bluetoothStateToggle + dialogDelegate.bluetoothStateToggle .onEach { - dialog.animateProgressBar(true) + dialogDelegate.animateProgressBar(dialog, true) bluetoothStateInteractor.isBluetoothEnabled = it } .launchIn(this) // deviceItemClick is emitted when user clicked on a device item. - dialog.deviceItemClick + dialogDelegate.deviceItemClick .onEach { deviceItemInteractor.updateDeviceItemOnClick(it) } .launchIn(this) // contentHeight is emitted when the dialog is dismissed. - dialog.contentHeight + dialogDelegate.contentHeight .onEach { withContext(backgroundDispatcher) { sharedPreferences.edit().putInt(CONTENT_HEIGHT_PREF_KEY, it).apply() @@ -191,12 +191,12 @@ constructor( // bluetoothAutoOnUpdate is emitted when bluetooth auto on on/off state is // changed. bluetoothAutoOnInteractor.isEnabled - .onEach { dialog.onBluetoothAutoOnUpdated(it) } + .onEach { dialogDelegate.onBluetoothAutoOnUpdated(dialog, it) } .launchIn(this) // bluetoothAutoOnToggle is emitted when user toggles the bluetooth auto on // switch, send the new value to the bluetoothAutoOnInteractor. - dialog.bluetoothAutoOnToggle + dialogDelegate.bluetoothAutoOnToggle .filterNotNull() .onEach { bluetoothAutoOnInteractor.setEnabled(it) } .launchIn(this) @@ -206,7 +206,7 @@ constructor( } } - private suspend fun createBluetoothTileDialog(context: Context): BluetoothTileDialog { + private suspend fun createBluetoothTileDialog(context: Context): BluetoothTileDialogDelegate { val cachedContentHeight = withContext(backgroundDispatcher) { sharedPreferences.getInt( @@ -215,21 +215,17 @@ constructor( ) } - return BluetoothTileDialog( + return bluetoothDialogDelegateFactory.create( + context, + UiProperties.build( bluetoothStateInteractor.isBluetoothEnabled, - UiProperties.build( - bluetoothStateInteractor.isBluetoothEnabled, - isAutoOnToggleFeatureAvailable() - ), - cachedContentHeight, - this@BluetoothTileDialogViewModel, - mainDispatcher, - systemClock, - uiEventLogger, - logger, - context - ) - .apply { SystemUIDialog.registerDismissListener(this) { cancelJob() } } + isAutoOnToggleFeatureAvailable() + ), + cachedContentHeight, + bluetoothStateInteractor.isBluetoothEnabled, + this@BluetoothTileDialogViewModel, + { cancelJob() } + ) } override fun onDeviceItemGearClicked(deviceItem: DeviceItem, view: View) { @@ -308,7 +304,7 @@ constructor( } } -internal interface BluetoothTileDialogCallback { +interface BluetoothTileDialogCallback { fun onDeviceItemGearClicked(deviceItem: DeviceItem, view: View) fun onSeeAllClicked(view: View) fun onPairNewDeviceClicked(view: View) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactory.kt index 1c9be0f105b2..f13ecf3e91b9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactory.kt @@ -21,6 +21,7 @@ import android.content.Context import android.media.AudioManager import com.android.settingslib.bluetooth.BluetoothUtils import com.android.settingslib.bluetooth.CachedBluetoothDevice +import com.android.settingslib.flags.Flags import com.android.systemui.res.R private val backgroundOn = R.drawable.settingslib_switch_bar_bg_on @@ -36,6 +37,7 @@ private val actionAccessibilityLabelDisconnect = /** Factories to create different types of Bluetooth device items from CachedBluetoothDevice. */ internal abstract class DeviceItemFactory { abstract fun isFilterMatched( + context: Context, cachedDevice: CachedBluetoothDevice, audioManager: AudioManager? ): Boolean @@ -45,6 +47,7 @@ internal abstract class DeviceItemFactory { internal class ActiveMediaDeviceItemFactory : DeviceItemFactory() { override fun isFilterMatched( + context: Context, cachedDevice: CachedBluetoothDevice, audioManager: AudioManager? ): Boolean { @@ -71,6 +74,7 @@ internal class ActiveMediaDeviceItemFactory : DeviceItemFactory() { internal class AvailableMediaDeviceItemFactory : DeviceItemFactory() { override fun isFilterMatched( + context: Context, cachedDevice: CachedBluetoothDevice, audioManager: AudioManager? ): Boolean { @@ -99,10 +103,18 @@ internal class AvailableMediaDeviceItemFactory : DeviceItemFactory() { internal class ConnectedDeviceItemFactory : DeviceItemFactory() { override fun isFilterMatched( + context: Context, cachedDevice: CachedBluetoothDevice, audioManager: AudioManager? ): Boolean { - return BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager) + return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) { + !BluetoothUtils.isExclusivelyManagedBluetoothDevice( + context, + cachedDevice.getDevice() + ) && BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager) + } else { + BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager) + } } override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem { @@ -125,10 +137,18 @@ internal class ConnectedDeviceItemFactory : DeviceItemFactory() { internal class SavedDeviceItemFactory : DeviceItemFactory() { override fun isFilterMatched( + context: Context, cachedDevice: CachedBluetoothDevice, audioManager: AudioManager? ): Boolean { - return cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected + return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) { + !BluetoothUtils.isExclusivelyManagedBluetoothDevice( + context, + cachedDevice.getDevice() + ) && cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected + } else { + cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected + } } override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt index fcd45a6431bb..1df496b17aa5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt @@ -133,7 +133,7 @@ constructor( bluetoothTileDialogRepository.cachedDevices .mapNotNull { cachedDevice -> deviceItemFactoryList - .firstOrNull { it.isFilterMatched(cachedDevice, audioManager) } + .firstOrNull { it.isFilterMatched(context, cachedDevice, audioManager) } ?.create(context, cachedDevice) } .sort(displayPriority, bluetoothAdapter?.mostRecentlyConnectedDevices) diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractor.kt new file mode 100644 index 000000000000..36350f8af455 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractor.kt @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package com.android.systemui.scene.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.scene.shared.flag.SceneContainerFlag +import com.android.systemui.scene.shared.model.ObservableTransitionState +import com.android.systemui.scene.shared.model.SceneKey +import com.android.systemui.shade.data.repository.ShadeRepository +import javax.inject.Inject +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map + +@SysUISingleton +class PanelExpansionInteractor +@Inject +constructor( + sceneInteractor: SceneInteractor, + shadeRepository: ShadeRepository, +) { + + /** + * The amount by which the "panel" has been expanded (`0` when fully collapsed, `1` when fully + * expanded). + * + * This is a legacy concept from the time when the "panel" included the notification/QS shades + * as well as the keyguard (lockscreen and bouncer). This value is meant only for + * backwards-compatibility and should not be consumed by newer code. + */ + @Deprecated("Use SceneInteractor.currentScene instead.") + val legacyPanelExpansion: Flow<Float> = + if (SceneContainerFlag.isEnabled) { + sceneInteractor.transitionState.flatMapLatest { state -> + when (state) { + is ObservableTransitionState.Idle -> + flowOf( + if (state.scene != SceneKey.Gone) { + // When resting on a non-Gone scene, the panel is fully expanded. + 1f + } else { + // When resting on the Gone scene, the panel is considered fully + // collapsed. + 0f + } + ) + is ObservableTransitionState.Transition -> + when { + state.fromScene == SceneKey.Gone -> + if (state.toScene.isExpandable()) { + // Moving from Gone to a scene that can animate-expand has a + // panel + // expansion + // that tracks with the transition. + state.progress + } else { + // Moving from Gone to a scene that doesn't animate-expand + // immediately makes + // the panel fully expanded. + flowOf(1f) + } + state.toScene == SceneKey.Gone -> + if (state.fromScene.isExpandable()) { + // Moving to Gone from a scene that can animate-expand has a + // panel + // expansion + // that tracks with the transition. + state.progress.map { 1 - it } + } else { + // Moving to Gone from a scene that doesn't animate-expand + // immediately makes + // the panel fully collapsed. + flowOf(0f) + } + else -> flowOf(1f) + } + } + } + } else { + shadeRepository.legacyShadeExpansion + } + + private fun SceneKey.isExpandable(): Boolean { + return this == SceneKey.Shade || this == SceneKey.QuickSettings + } +} diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt index b642d38289fe..034f87f4c72f 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt @@ -26,6 +26,7 @@ import com.android.systemui.bouncer.domain.interactor.BouncerInteractor import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.FalsingCollectorActual +import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.DisplayId @@ -34,6 +35,8 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.model.SceneContainerPlugin import com.android.systemui.model.SysUiState import com.android.systemui.model.updateFlags +import com.android.systemui.plugins.FalsingManager +import com.android.systemui.plugins.FalsingManager.FalsingBeliefListener import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.flag.SceneContainerFlags @@ -53,6 +56,7 @@ import java.io.PrintWriter import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged @@ -82,6 +86,7 @@ constructor( @DisplayId private val displayId: Int, private val sceneLogger: SceneLogger, @FalsingCollectorActual private val falsingCollector: FalsingCollector, + private val falsingManager: FalsingManager, private val powerInteractor: PowerInteractor, private val simBouncerInteractor: Lazy<SimBouncerInteractor>, private val authenticationInteractor: Lazy<AuthenticationInteractor>, @@ -98,6 +103,7 @@ constructor( automaticallySwitchScenes() hydrateSystemUiState() collectFalsingSignals() + respondToFalsingDetections() hydrateWindowFocus() hydrateInteractionState() } else { @@ -376,6 +382,18 @@ constructor( } } + /** Switches to the lockscreen when falsing is detected. */ + private fun respondToFalsingDetections() { + applicationScope.launch { + conflatedCallbackFlow { + val listener = FalsingBeliefListener { trySend(Unit) } + falsingManager.addFalsingBeliefListener(listener) + awaitClose { falsingManager.removeFalsingBeliefListener(listener) } + } + .collect { switchToScene(SceneKey.Lockscreen, "Falsing detected.") } + } + } + /** Keeps the focus state of the window view up-to-date. */ private fun hydrateWindowFocus() { applicationScope.launch { diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/UserActionResult.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/UserActionResult.kt index e1b96e4db938..c6ae21505c68 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/UserActionResult.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/UserActionResult.kt @@ -22,13 +22,6 @@ data class UserActionResult( val toScene: SceneKey, /** - * The distance the action takes to animate from 0% to 100%. - * - * If `null`, a default distance will be used depending on the [UserAction] performed. - */ - val distance: UserActionDistance? = null, - - /** * The key of the transition that should be used, if a specific one should be used. * * If `null`, the transition used will be the corresponding transition from the collection diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt index 45b6f65d5d67..ee76c0582b9d 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt @@ -16,11 +16,9 @@ package com.android.systemui.scene.ui.view -import android.view.Gravity import android.view.View import android.view.ViewGroup import android.view.WindowInsets -import android.widget.FrameLayout import androidx.activity.OnBackPressedDispatcher import androidx.activity.OnBackPressedDispatcherOwner import androidx.activity.setViewTreeOnBackPressedDispatcherOwner @@ -39,7 +37,6 @@ import com.android.systemui.scene.shared.model.SceneKey import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer -import java.time.Instant import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @@ -98,7 +95,7 @@ object SceneWindowRootViewBinder { ) val legacyView = view.requireViewById<View>(R.id.legacy_window_root) - view.addView(createVisibilityToggleView(legacyView)) + legacyView.isVisible = false // This moves the SharedNotificationContainer to the WindowRootView just after // the SceneContainerView. This SharedNotificationContainer should contain NSSL @@ -123,29 +120,4 @@ object SceneWindowRootViewBinder { } } } - - private var clickCount = 0 - private var lastClick = Instant.now() - - /** - * A temporary UI to toggle on/off the visibility of the given [otherView]. It is toggled by - * tapping 5 times in quick succession on the device camera (top center). - */ - // TODO(b/291321285): Remove this when the Flexiglass UI is mature enough to turn off legacy - // SysUI altogether. - private fun createVisibilityToggleView(otherView: View): View { - val toggleView = View(otherView.context) - otherView.isVisible = false - toggleView.layoutParams = FrameLayout.LayoutParams(200, 200, Gravity.CENTER_HORIZONTAL) - toggleView.setOnClickListener { - val now = Instant.now() - clickCount = if (now.minusSeconds(2) > lastClick) 1 else clickCount + 1 - if (clickCount == 5) { - otherView.isVisible = !otherView.isVisible - clickCount = 0 - } - lastClick = now - } - return toggleView - } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt index fb5339df7212..1f9853b17a28 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt @@ -16,6 +16,8 @@ package com.android.systemui.screenshot +import android.app.ActivityOptions +import android.app.ExitTransitionCoordinator import android.content.Context import android.content.Intent import android.os.Bundle @@ -23,6 +25,7 @@ import android.os.Process.myUserHandle import android.os.RemoteException import android.os.UserHandle import android.util.Log +import android.util.Pair import android.view.IRemoteAnimationFinishedCallback import android.view.IRemoteAnimationRunner import android.view.RemoteAnimationAdapter @@ -64,18 +67,18 @@ constructor( */ fun launchIntentAsync( intent: Intent, - options: Bundle?, + transition: Pair<ActivityOptions, ExitTransitionCoordinator>?, user: UserHandle, overrideTransition: Boolean, ) { applicationScope.launch("$TAG#launchIntentAsync") { - launchIntent(intent, options, user, overrideTransition) + launchIntent(intent, transition, user, overrideTransition) } } suspend fun launchIntent( intent: Intent, - options: Bundle?, + transition: Pair<ActivityOptions, ExitTransitionCoordinator>?, user: UserHandle, overrideTransition: Boolean, ) { @@ -87,11 +90,14 @@ constructor( } else { dismissKeyguard() } + transition?.second?.startExit() if (user == myUserHandle()) { - withContext(mainDispatcher) { context.startActivity(intent, options) } + withContext(mainDispatcher) { + context.startActivity(intent, transition?.first?.toBundle()) + } } else { - launchCrossProfileIntent(user, intent, options) + launchCrossProfileIntent(user, intent, transition?.first?.toBundle()) } if (overrideTransition) { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java index 0588fe2bba82..30f5e8b50bf4 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/OverlayActionChip.java @@ -18,6 +18,7 @@ package com.android.systemui.screenshot; import static java.util.Objects.requireNonNull; +import android.app.ActivityOptions; import android.app.BroadcastOptions; import android.app.PendingIntent; import android.content.Context; @@ -100,7 +101,7 @@ public class OverlayActionChip extends FrameLayout { BroadcastOptions options = BroadcastOptions.makeBasic(); options.setInteractive(true); options.setPendingIntentBackgroundActivityStartMode( - BroadcastOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED); + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED); intent.send(options.toBundle()); finisher.run(); } catch (PendingIntent.CanceledException e) { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java index 31086d85f747..bbf7ed529220 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java @@ -16,40 +16,29 @@ package com.android.systemui.screenshot; -import static com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS; import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK; import static com.android.systemui.screenshot.LogConfig.DEBUG_STORAGE; import static com.android.systemui.screenshot.LogConfig.logTag; import static com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider.ScreenshotSmartActionType; -import android.app.ActivityTaskManager; import android.app.Notification; import android.app.PendingIntent; import android.content.ClipData; import android.content.ClipDescription; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.UserInfo; -import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.drawable.Icon; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Process; -import android.os.RemoteException; import android.os.UserHandle; -import android.os.UserManager; import android.provider.DeviceConfig; -import android.text.TextUtils; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; -import com.android.systemui.res.R; import com.android.systemui.flags.FeatureFlags; -import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition; import com.google.common.util.concurrent.ListenableFuture; @@ -60,7 +49,6 @@ import java.util.List; import java.util.Random; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import java.util.function.Supplier; /** * An AsyncTask that saves an image to the media store in the background. @@ -81,7 +69,6 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { private final ScreenshotNotificationSmartActionsProvider mSmartActionsProvider; private String mScreenshotId; private final Random mRandom = new Random(); - private final Supplier<ActionTransition> mSharedElementTransition; private final ImageExporter mImageExporter; private long mImageTime; @@ -91,7 +78,6 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { ImageExporter exporter, ScreenshotSmartActions screenshotSmartActions, ScreenshotController.SaveImageInBackgroundData data, - Supplier<ActionTransition> sharedElementTransition, ScreenshotNotificationSmartActionsProvider screenshotNotificationSmartActionsProvider ) { @@ -100,7 +86,6 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { mScreenshotSmartActions = screenshotSmartActions; mImageData = new ScreenshotController.SavedImageData(); mQuickShareData = new ScreenshotController.QuickShareData(); - mSharedElementTransition = sharedElementTransition; mImageExporter = exporter; // Prepare all the output metadata @@ -176,12 +161,6 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { mImageData.uri = uri; mImageData.owner = mParams.owner; mImageData.smartActions = smartActions; - mImageData.shareTransition = createShareAction(mContext, mContext.getResources(), uri, - smartActionsEnabled); - mImageData.editTransition = createEditAction(mContext, mContext.getResources(), uri, - smartActionsEnabled); - mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri, - smartActionsEnabled); mImageData.quickShareAction = createQuickShareAction( mQuickShareData.quickShareAction, mScreenshotId, uri, mImageTime, image, mParams.owner); @@ -234,164 +213,6 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { mParams.clearImage(); } - /** - * Assumes that the action intent is sent immediately after being supplied. - */ - @VisibleForTesting - Supplier<ActionTransition> createShareAction(Context context, Resources r, Uri uri, - boolean smartActionsEnabled) { - return () -> { - ActionTransition transition = mSharedElementTransition.get(); - - // Note: Both the share and edit actions are proxied through ActionProxyReceiver in - // order to do some common work like dismissing the keyguard and sending - // closeSystemWindows - - // Create a share intent, this will always go through the chooser activity first - // which should not trigger auto-enter PiP - Intent sharingIntent = new Intent(Intent.ACTION_SEND); - sharingIntent.setDataAndType(uri, "image/png"); - sharingIntent.putExtra(Intent.EXTRA_STREAM, uri); - // Include URI in ClipData also, so that grantPermission picks it up. - // We don't use setData here because some apps interpret this as "to:". - ClipData clipdata = new ClipData(new ClipDescription("content", - new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}), - new ClipData.Item(uri)); - sharingIntent.setClipData(clipdata); - sharingIntent.putExtra(Intent.EXTRA_SUBJECT, getSubjectString(mImageTime)); - sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - .addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - - - // Make sure pending intents for the system user are still unique across users - // by setting the (otherwise unused) request code to the current user id. - int requestCode = context.getUserId(); - - Intent sharingChooserIntent = Intent.createChooser(sharingIntent, null) - .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK) - .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - - - // cancel current pending intent (if any) since clipData isn't used for matching - PendingIntent pendingIntent = PendingIntent.getActivityAsUser( - context, 0, sharingChooserIntent, - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE, - transition.bundle, UserHandle.CURRENT); - - // Create a share action for the notification - PendingIntent shareAction = PendingIntent.getBroadcastAsUser(context, requestCode, - new Intent(context, ActionProxyReceiver.class) - .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, pendingIntent) - .putExtra(ScreenshotController.EXTRA_DISALLOW_ENTER_PIP, true) - .putExtra(ScreenshotController.EXTRA_ID, mScreenshotId) - .putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED, - smartActionsEnabled) - .setAction(Intent.ACTION_SEND) - .addFlags(Intent.FLAG_RECEIVER_FOREGROUND), - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE, - UserHandle.SYSTEM); - - Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder( - Icon.createWithResource(r, R.drawable.ic_screenshot_share), - r.getString(com.android.internal.R.string.share), shareAction); - - transition.action = shareActionBuilder.build(); - return transition; - }; - } - - @VisibleForTesting - Supplier<ActionTransition> createEditAction(Context context, Resources r, Uri uri, - boolean smartActionsEnabled) { - return () -> { - ActionTransition transition = mSharedElementTransition.get(); - // Note: Both the share and edit actions are proxied through ActionProxyReceiver in - // order to do some common work like dismissing the keyguard and sending - // closeSystemWindows - - // Create an edit intent, if a specific package is provided as the editor, then - // launch that directly - String editorPackage = context.getString(R.string.config_screenshotEditor); - Intent editIntent = new Intent(Intent.ACTION_EDIT); - if (!TextUtils.isEmpty(editorPackage)) { - editIntent.setComponent(ComponentName.unflattenFromString(editorPackage)); - } - editIntent.setDataAndType(uri, "image/png"); - editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - - PendingIntent pendingIntent = PendingIntent.getActivityAsUser( - context, 0, editIntent, PendingIntent.FLAG_IMMUTABLE, - transition.bundle, UserHandle.CURRENT); - - // Make sure pending intents for the system user are still unique across users - // by setting the (otherwise unused) request code to the current user id. - int requestCode = mContext.getUserId(); - - // Create an edit action - PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode, - new Intent(context, ActionProxyReceiver.class) - .putExtra(ScreenshotController.EXTRA_ACTION_INTENT, pendingIntent) - .putExtra(ScreenshotController.EXTRA_ID, mScreenshotId) - .putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED, - smartActionsEnabled) - .putExtra(ScreenshotController.EXTRA_OVERRIDE_TRANSITION, true) - .setAction(Intent.ACTION_EDIT) - .addFlags(Intent.FLAG_RECEIVER_FOREGROUND), - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE, - UserHandle.SYSTEM); - Notification.Action.Builder editActionBuilder = new Notification.Action.Builder( - Icon.createWithResource(r, R.drawable.ic_screenshot_edit), - r.getString(com.android.internal.R.string.screenshot_edit), editAction); - - transition.action = editActionBuilder.build(); - return transition; - }; - } - - @VisibleForTesting - Notification.Action createDeleteAction(Context context, Resources r, Uri uri, - boolean smartActionsEnabled) { - // Make sure pending intents for the system user are still unique across users - // by setting the (otherwise unused) request code to the current user id. - int requestCode = mContext.getUserId(); - - // Create a delete action for the notification - PendingIntent deleteAction = PendingIntent.getBroadcast(context, requestCode, - new Intent(context, DeleteScreenshotReceiver.class) - .putExtra(ScreenshotController.SCREENSHOT_URI_ID, uri.toString()) - .putExtra(ScreenshotController.EXTRA_ID, mScreenshotId) - .putExtra(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED, - smartActionsEnabled) - .addFlags(Intent.FLAG_RECEIVER_FOREGROUND), - PendingIntent.FLAG_CANCEL_CURRENT - | PendingIntent.FLAG_ONE_SHOT - | PendingIntent.FLAG_IMMUTABLE); - Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder( - Icon.createWithResource(r, R.drawable.ic_screenshot_delete), - r.getString(com.android.internal.R.string.delete), deleteAction); - - return deleteActionBuilder.build(); - } - - private UserHandle getUserHandleOfForegroundApplication(Context context) { - UserManager manager = UserManager.get(context); - int result; - // This logic matches - // com.android.systemui.statusbar.phone.PhoneStatusBarPolicy#updateManagedProfile - try { - result = ActivityTaskManager.getService().getLastResumedActivityUserId(); - } catch (RemoteException e) { - if (DEBUG_ACTIONS) { - Log.d(TAG, "Failed to get UserHandle of foreground app: ", e); - } - result = context.getUserId(); - } - UserInfo userInfo = manager.getUserInfo(result); - return userInfo.getUserHandle(); - } - private List<Notification.Action> buildSmartActions( List<Notification.Action> actions, Context context) { List<Notification.Action> broadcastActions = new ArrayList<>(); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index 21a08a9a4980..ee3e7ba9e8b3 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -39,7 +39,6 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ExitTransitionCoordinator; -import android.app.ExitTransitionCoordinator.ExitTransitionCallbacks; import android.app.ICompatCameraControlCallback; import android.app.Notification; import android.app.assist.AssistContent; @@ -54,7 +53,6 @@ import android.graphics.Insets; import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.net.Uri; -import android.os.Bundle; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; @@ -87,13 +85,12 @@ import com.android.internal.app.ChooserActivity; import com.android.internal.logging.UiEventLogger; import com.android.internal.policy.PhoneWindow; import com.android.settingslib.applications.InterestingConfigChanges; -import com.android.systemui.res.R; import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.clipboardoverlay.ClipboardOverlayController; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; -import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition; +import com.android.systemui.res.R; import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback; import com.android.systemui.util.Assert; @@ -111,7 +108,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.function.Consumer; -import java.util.function.Supplier; import javax.inject.Provider; @@ -171,31 +167,16 @@ public class ScreenshotController { */ static class SavedImageData { public Uri uri; - public Supplier<ActionTransition> shareTransition; - public Supplier<ActionTransition> editTransition; - public Notification.Action deleteAction; public List<Notification.Action> smartActions; public Notification.Action quickShareAction; public UserHandle owner; public String subject; // Title for sharing /** - * POD for shared element transition. - */ - static class ActionTransition { - public Bundle bundle; - public Notification.Action action; - public Runnable onCancelRunnable; - } - - /** * Used to reset the return data on error */ public void reset() { uri = null; - shareTransition = null; - editTransition = null; - deleteAction = null; smartActions = null; quickShareAction = null; subject = null; @@ -469,8 +450,9 @@ public class ScreenshotController { if (!shouldShowUi()) { saveScreenshotInWorkerThread( - screenshot.getUserHandle(), finisher, this::logSuccessOnActionsReady, - (ignored) -> {}); + screenshot.getUserHandle(), finisher, this::logSuccessOnActionsReady, + (ignored) -> { + }); return; } @@ -489,7 +471,7 @@ public class ScreenshotController { if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE) { if (screenshot.getScreenBounds() != null && aspectRatiosMatch(screenshot.getBitmap(), screenshot.getInsets(), - screenshot.getScreenBounds())) { + screenshot.getScreenBounds())) { showFlash = false; } else { showFlash = true; @@ -643,6 +625,12 @@ public class ScreenshotController { } @Override + public void onAction(Intent intent, UserHandle owner, boolean overrideTransition) { + mActionExecutor.launchIntentAsync( + intent, createWindowTransition(), owner, overrideTransition); + } + + @Override public void onDismiss() { finishDismiss(); } @@ -652,7 +640,7 @@ public class ScreenshotController { // TODO(159460485): Remove this when focus is handled properly in the system setWindowFocusable(false); } - }, mActionExecutor, mFlags); + }, mFlags); mScreenshotView.setDefaultDisplay(mDisplayId); mScreenshotView.setDefaultTimeoutMillis(mScreenshotHandler.getDefaultTimeoutMillis()); @@ -964,6 +952,35 @@ public class ScreenshotController { mScreenshotAnimation.start(); } + /** + * Supplies the necessary bits for the shared element transition to share sheet. + * Note that once called, the action intent to share must be sent immediately after. + */ + private Pair<ActivityOptions, ExitTransitionCoordinator> createWindowTransition() { + ExitTransitionCoordinator.ExitTransitionCallbacks callbacks = + new ExitTransitionCoordinator.ExitTransitionCallbacks() { + @Override + public boolean isReturnTransitionAllowed() { + return false; + } + + @Override + public void hideSharedElements() { + finishDismiss(); + } + + @Override + public void onFinish() { + } + }; + Pair<ActivityOptions, ExitTransitionCoordinator> transition = + ActivityOptions.startSharedElementAnimation(mWindow, callbacks, null, + Pair.create(mScreenshotView.getScreenshotPreview(), + ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME)); + + return transition; + } + /** Reset screenshot view and then call onCompleteRunnable */ private void finishDismiss() { Log.d(TAG, "finishDismiss"); @@ -1011,7 +1028,7 @@ public class ScreenshotController { } mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mFlags, mImageExporter, - mScreenshotSmartActions, data, getActionTransitionSupplier(), + mScreenshotSmartActions, data, mScreenshotNotificationSmartActionsProvider); mSaveInBgTask.execute(); } @@ -1078,26 +1095,6 @@ public class ScreenshotController { } /** - * Supplies the necessary bits for the shared element transition to share sheet. - * Note that once supplied, the action intent to share must be sent immediately after. - */ - private Supplier<ActionTransition> getActionTransitionSupplier() { - return () -> { - Pair<ActivityOptions, ExitTransitionCoordinator> transition = - ActivityOptions.startSharedElementAnimation( - mWindow, new ScreenshotExitTransitionCallbacksSupplier(true).get(), - null, Pair.create(mScreenshotView.getScreenshotPreview(), - ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME)); - transition.second.startExit(); - - ActionTransition supply = new ActionTransition(); - supply.bundle = transition.first.toBundle(); - supply.onCancelRunnable = () -> ActivityOptions.stopSharedElementAnimation(mWindow); - return supply; - }; - } - - /** * Logs success/failure of the screenshot saving task, and shows an error if it failed. */ private void logSuccessOnActionsReady(ScreenshotController.SavedImageData imageData) { @@ -1186,36 +1183,6 @@ public class ScreenshotController { return matchWithinTolerance; } - private class ScreenshotExitTransitionCallbacksSupplier implements - Supplier<ExitTransitionCallbacks> { - final boolean mDismissOnHideSharedElements; - - ScreenshotExitTransitionCallbacksSupplier(boolean dismissOnHideSharedElements) { - mDismissOnHideSharedElements = dismissOnHideSharedElements; - } - - @Override - public ExitTransitionCallbacks get() { - return new ExitTransitionCallbacks() { - @Override - public boolean isReturnTransitionAllowed() { - return false; - } - - @Override - public void hideSharedElements() { - if (mDismissOnHideSharedElements) { - finishDismiss(); - } - } - - @Override - public void onFinish() { - } - }; - } - } - /** Injectable factory to create screenshot controller instances for a specific display. */ @AssistedFactory public interface Factory { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java index 31c928406aac..be30a1576b21 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java @@ -57,6 +57,7 @@ import android.graphics.drawable.LayerDrawable; import android.os.Bundle; import android.os.Looper; import android.os.RemoteException; +import android.os.UserHandle; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -86,9 +87,9 @@ import androidx.constraintlayout.widget.ConstraintLayout; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.logging.UiEventLogger; -import com.android.systemui.res.R; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; +import com.android.systemui.res.R; import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.QuickStepContract; @@ -104,6 +105,8 @@ public class ScreenshotView extends FrameLayout implements interface ScreenshotViewCallback { void onUserInteraction(); + void onAction(Intent intent, UserHandle owner, boolean overrideTransition); + void onDismiss(); /** DOWN motion event was observed outside of the touchable areas of this view. */ @@ -166,7 +169,6 @@ public class ScreenshotView extends FrameLayout implements private final InteractionJankMonitor mInteractionJankMonitor; private long mDefaultTimeoutOfTimeoutHandler; - private ActionIntentExecutor mActionExecutor; private FeatureFlags mFlags; private final Bundle mInteractiveBroadcastOption; @@ -430,11 +432,9 @@ public class ScreenshotView extends FrameLayout implements * Note: must be called before any other (non-constructor) method or null pointer exceptions * may occur. */ - void init(UiEventLogger uiEventLogger, ScreenshotViewCallback callbacks, - ActionIntentExecutor actionExecutor, FeatureFlags flags) { + void init(UiEventLogger uiEventLogger, ScreenshotViewCallback callbacks, FeatureFlags flags) { mUiEventLogger = uiEventLogger; mCallbacks = callbacks; - mActionExecutor = actionExecutor; mFlags = flags; } @@ -800,24 +800,21 @@ public class ScreenshotView extends FrameLayout implements shareIntent = ActionIntentCreator.INSTANCE.createShareWithSubject( imageData.uri, imageData.subject); } - mActionExecutor.launchIntentAsync(shareIntent, - imageData.shareTransition.get().bundle, - imageData.owner, false); + mCallbacks.onAction(shareIntent, imageData.owner, false); + }); mEditChip.setOnClickListener(v -> { mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED, 0, mPackageName); prepareSharedTransition(); - mActionExecutor.launchIntentAsync( + mCallbacks.onAction( ActionIntentCreator.INSTANCE.createEdit(imageData.uri, mContext), - imageData.editTransition.get().bundle, imageData.owner, true); }); mScreenshotPreview.setOnClickListener(v -> { mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED, 0, mPackageName); prepareSharedTransition(); - mActionExecutor.launchIntentAsync( + mCallbacks.onAction( ActionIntentCreator.INSTANCE.createEdit(imageData.uri, mContext), - imageData.editTransition.get().bundle, imageData.owner, true); }); if (mQuickShareChip != null) { diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt index 125f7fc0619b..0a1f649691a1 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt @@ -227,22 +227,10 @@ open class UserTrackerImpl internal constructor( protected open fun handleBeforeUserSwitching(newUserId: Int) { setUserIdInternal(newUserId) - val list = synchronized(callbacks) { - callbacks.toList() - } - val latch = CountDownLatch(list.size) - list.forEach { - val callback = it.callback.get() - if (callback != null) { - it.executor.execute { - callback.onBeforeUserSwitching(newUserId) - latch.countDown() - } - } else { - latch.countDown() - } - } - latch.await() + notifySubscribers { callback, resultCallback -> + callback.onBeforeUserSwitching(newUserId) + resultCallback.run() + }.await() } @WorkerThread @@ -250,21 +238,9 @@ open class UserTrackerImpl internal constructor( Assert.isNotMainThread() Log.i(TAG, "Switching to user $newUserId") - val list = synchronized(callbacks) { - callbacks.toList() - } - val latch = CountDownLatch(list.size) - list.forEach { - val callback = it.callback.get() - if (callback != null) { - it.executor.execute { - callback.onUserChanging(userId, userContext) { latch.countDown() } - } - } else { - latch.countDown() - } - } - latch.await() + notifySubscribers { callback, resultCallback -> + callback.onUserChanging(newUserId, userContext, resultCallback) + }.await() } @WorkerThread @@ -294,9 +270,9 @@ open class UserTrackerImpl internal constructor( Assert.isNotMainThread() Log.i(TAG, "Switched to user $newUserId") - notifySubscribers { - onUserChanged(newUserId, userContext) - onProfilesChanged(userProfiles) + notifySubscribers { callback, _ -> + callback.onUserChanged(newUserId, userContext) + callback.onProfilesChanged(userProfiles) } } @@ -308,8 +284,8 @@ open class UserTrackerImpl internal constructor( synchronized(mutex) { userProfiles = profiles.map { UserInfo(it) } // save a "deep" copy } - notifySubscribers { - onProfilesChanged(profiles) + notifySubscribers { callback, _ -> + callback.onProfilesChanged(profiles) } } @@ -325,18 +301,24 @@ open class UserTrackerImpl internal constructor( } } - private inline fun notifySubscribers(crossinline action: UserTracker.Callback.() -> Unit) { + private inline fun notifySubscribers( + crossinline action: (UserTracker.Callback, resultCallback: Runnable) -> Unit + ): CountDownLatch { val list = synchronized(callbacks) { callbacks.toList() } - + val latch = CountDownLatch(list.size) list.forEach { - if (it.callback.get() != null) { + val callback = it.callback.get() + if (callback != null) { it.executor.execute { - it.callback.get()?.action() + action(callback) { latch.countDown() } } + } else { + latch.countDown() } } + return latch } override fun dump(pw: PrintWriter, args: Array<out String>) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 7068f5fcc32b..7b330b0f3803 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -1201,7 +1201,12 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump // Primary bouncer->Gone (ensures lockscreen content is not visible on successful auth) if (!migrateClocksToBlueprint()) { collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha(), - setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher); + setTransitionAlpha(mNotificationStackScrollLayoutController, + /* excludeNotifications=*/ true), mMainDispatcher); + collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getNotificationAlpha(), + (Float alpha) -> { + mNotificationStackScrollLayoutController.setMaxAlphaForExpansion(alpha); + }, mMainDispatcher); } } @@ -1539,6 +1544,7 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump @Override public void setOpenCloseListener(OpenCloseListener openCloseListener) { + SceneContainerFlag.assertInLegacyMode(); mOpenCloseListener = openCloseListener; } @@ -4724,9 +4730,17 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump private Consumer<Float> setTransitionAlpha( NotificationStackScrollLayoutController stackScroller) { + return setTransitionAlpha(stackScroller, /* excludeNotifications= */ false); + } + + private Consumer<Float> setTransitionAlpha( + NotificationStackScrollLayoutController stackScroller, + boolean excludeNotifications) { return (Float alpha) -> { mKeyguardStatusViewController.setAlpha(alpha); - stackScroller.setMaxAlphaForExpansion(alpha); + if (!excludeNotifications) { + stackScroller.setMaxAlphaForExpansion(alpha); + } if (keyguardBottomAreaRefactor()) { mKeyguardInteractor.setAlpha(alpha); diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java index e7f970050033..a5c055350999 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsController.java @@ -282,12 +282,6 @@ public class QuickSettingsController implements Dumpable { /** The duration of the notification bounds animation. */ private long mNotificationBoundsAnimationDuration; - /** TODO(b/273591201): remove after bug resolved */ - private int mLastClippingTopBound; - private int mLastNotificationsTopPadding; - private int mLastNotificationsClippingTopBound; - private int mLastNotificationsClippingTopBoundNssl; - private final Region mInterceptRegion = new Region(); /** The end bounds of a clipping animation. */ private final Rect mClippingAnimationEndBounds = new Rect(); @@ -2141,14 +2135,6 @@ public class QuickSettingsController implements Dumpable { ipw.println(mNotificationBoundsAnimationDelay); ipw.print("mNotificationBoundsAnimationDuration="); ipw.println(mNotificationBoundsAnimationDuration); - ipw.print("mLastClippingTopBound="); - ipw.println(mLastClippingTopBound); - ipw.print("mLastNotificationsTopPadding="); - ipw.println(mLastNotificationsTopPadding); - ipw.print("mLastNotificationsClippingTopBound="); - ipw.println(mLastNotificationsClippingTopBound); - ipw.print("mLastNotificationsClippingTopBoundNssl="); - ipw.println(mLastNotificationsClippingTopBoundNssl); ipw.print("mInterceptRegion="); ipw.println(mInterceptRegion); ipw.print("mClippingAnimationEndBounds="); diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java index ea419127d7c1..e6555f2e0993 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java @@ -32,6 +32,7 @@ import com.android.systemui.log.LogBuffer; import com.android.systemui.log.dagger.ShadeTouchLog; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor; +import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.StatusBarState; @@ -98,6 +99,7 @@ public final class ShadeControllerImpl extends BaseShadeControllerImpl { statusBarKeyguardViewManager, notificationShadeWindowController, assistManagerLazy); + SceneContainerFlag.assertInLegacyMode(); mCommandQueue = commandQueue; mMainExecutor = mainExecutor; mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor; diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt index 971507055873..84afbed51faa 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt @@ -19,8 +19,11 @@ package com.android.systemui.shade.transition import android.content.Context import android.content.res.Configuration import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dump.DumpManager import com.android.systemui.plugins.qs.QS +import com.android.systemui.scene.domain.interactor.PanelExpansionInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.PanelState import com.android.systemui.shade.ShadeExpansionChangeEvent import com.android.systemui.shade.ShadeExpansionStateManager @@ -31,21 +34,26 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.SplitShadeStateController +import dagger.Lazy import java.io.PrintWriter import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch /** Controls the shade expansion transition on non-lockscreen. */ @SysUISingleton class ShadeTransitionController @Inject constructor( + @Application private val applicationScope: CoroutineScope, configurationController: ConfigurationController, shadeExpansionStateManager: ShadeExpansionStateManager, dumpManager: DumpManager, private val context: Context, private val scrimShadeTransitionController: ScrimShadeTransitionController, private val statusBarStateController: SysuiStatusBarStateController, - private val splitShadeStateController: SplitShadeStateController + private val splitShadeStateController: SplitShadeStateController, + private val panelExpansionInteractor: Lazy<PanelExpansionInteractor>, ) { lateinit var shadeViewController: ShadeViewController @@ -63,11 +71,27 @@ constructor( override fun onConfigChanged(newConfig: Configuration?) { updateResources() } - }) - val currentState = - shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged) - onPanelExpansionChanged(currentState) - shadeExpansionStateManager.addStateListener(this::onPanelStateChanged) + } + ) + if (SceneContainerFlag.isEnabled) { + applicationScope.launch { + panelExpansionInteractor.get().legacyPanelExpansion.collect { panelExpansion -> + onPanelExpansionChanged( + ShadeExpansionChangeEvent( + fraction = panelExpansion, + expanded = panelExpansion > 0f, + tracking = true, + dragDownPxAmount = 0f, + ) + ) + } + } + } else { + val currentState = + shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged) + onPanelExpansionChanged(currentState) + shadeExpansionStateManager.addStateListener(this::onPanelStateChanged) + } dumpManager.registerCriticalDumpable("ShadeTransitionController") { printWriter, _ -> dump(printWriter) } @@ -98,7 +122,9 @@ constructor( qs.isInitialized: ${this::qs.isInitialized} npvc.isInitialized: ${this::shadeViewController.isInitialized} nssl.isInitialized: ${this::notificationStackScrollLayoutController.isInitialized} - """.trimIndent()) + """ + .trimIndent() + ) } private fun isScreenUnlocked() = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt index 835225009110..a58ce4162ddc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BatteryStatusChip.kt @@ -22,7 +22,9 @@ import android.util.AttributeSet import android.view.View import android.widget.FrameLayout import android.widget.LinearLayout +import com.android.settingslib.flags.Flags.newStatusBarIcons import com.android.systemui.battery.BatteryMeterView +import com.android.systemui.battery.unified.BatteryColors import com.android.systemui.res.R import com.android.systemui.statusbar.events.BackgroundAnimatableView @@ -39,8 +41,12 @@ class BatteryStatusChip @JvmOverloads constructor(context: Context, attrs: Attri roundedContainer = requireViewById(R.id.rounded_container) batteryMeterView = requireViewById(R.id.battery_meter_view) batteryMeterView.setStaticColor(true) - val primaryColor = context.resources.getColor(android.R.color.black, context.theme) - batteryMeterView.updateColors(primaryColor, primaryColor, primaryColor) + if (newStatusBarIcons()) { + batteryMeterView.setUnifiedBatteryColors(BatteryColors.LightThemeColors) + } else { + val primaryColor = context.resources.getColor(android.R.color.black, context.theme) + batteryMeterView.updateColors(primaryColor, primaryColor, primaryColor) + } updateResources() } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 3908edec7da5..bb8168335b60 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -168,7 +168,7 @@ public class CommandQueue extends IStatusBar.Stub implements private static final int MSG_UNREGISTER_NEARBY_MEDIA_DEVICE_PROVIDER = 67 << MSG_SHIFT; private static final int MSG_TILE_SERVICE_REQUEST_LISTENING_STATE = 68 << MSG_SHIFT; private static final int MSG_SHOW_REAR_DISPLAY_DIALOG = 69 << MSG_SHIFT; - private static final int MSG_GO_TO_FULLSCREEN_FROM_SPLIT = 70 << MSG_SHIFT; + private static final int MSG_MOVE_FOCUSED_TASK_TO_FULLSCREEN = 70 << MSG_SHIFT; private static final int MSG_ENTER_STAGE_SPLIT_FROM_RUNNING_APP = 71 << MSG_SHIFT; private static final int MSG_SHOW_MEDIA_OUTPUT_SWITCHER = 72 << MSG_SHIFT; private static final int MSG_TOGGLE_TASKBAR = 73 << MSG_SHIFT; @@ -498,9 +498,9 @@ public class CommandQueue extends IStatusBar.Stub implements default void showRearDisplayDialog(int currentBaseState) {} /** - * @see IStatusBar#goToFullscreenFromSplit + * @see IStatusBar#moveFocusedTaskToFullscreen */ - default void goToFullscreenFromSplit() {} + default void moveFocusedTaskToFullscreen(int displayId) {} /** * @see IStatusBar#enterStageSplitFromRunningApp @@ -615,7 +615,14 @@ public class CommandQueue extends IStatusBar.Stub implements args.argi2 = state1; args.argi3 = state2; args.argi4 = animate ? 1 : 0; - mHandler.obtainMessage(MSG_DISABLE, args).sendToTarget(); + Message msg = mHandler.obtainMessage(MSG_DISABLE, args); + if (Looper.myLooper() == mHandler.getLooper()) { + // If its the right looper execute immediately so hides can be handled quickly. + mHandler.handleMessage(msg); + msg.recycle(); + } else { + msg.sendToTarget(); + } } } @@ -1415,8 +1422,10 @@ public class CommandQueue extends IStatusBar.Stub implements } @Override - public void goToFullscreenFromSplit() { - mHandler.obtainMessage(MSG_GO_TO_FULLSCREEN_FROM_SPLIT).sendToTarget(); + public void moveFocusedTaskToFullscreen(int displayId) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = displayId; + mHandler.obtainMessage(MSG_MOVE_FOCUSED_TASK_TO_FULLSCREEN, args).sendToTarget(); } @Override @@ -1890,11 +1899,14 @@ public class CommandQueue extends IStatusBar.Stub implements mCallbacks.get(i).showRearDisplayDialog((Integer) msg.obj); } break; - case MSG_GO_TO_FULLSCREEN_FROM_SPLIT: + case MSG_MOVE_FOCUSED_TASK_TO_FULLSCREEN: { + args = (SomeArgs) msg.obj; + int displayId = args.argi1; for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).goToFullscreenFromSplit(); + mCallbacks.get(i).moveFocusedTaskToFullscreen(displayId); } break; + } case MSG_ENTER_STAGE_SPLIT_FROM_RUNNING_APP: for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).enterStageSplitFromRunningApp((Boolean) msg.obj); @@ -1920,13 +1932,14 @@ public class CommandQueue extends IStatusBar.Stub implements mCallbacks.get(i).immersiveModeChanged(rootDisplayAreaId, isImmersiveMode); } break; - case MSG_ENTER_DESKTOP: + case MSG_ENTER_DESKTOP: { args = (SomeArgs) msg.obj; int displayId = args.argi1; for (int i = 0; i < mCallbacks.size(); i++) { mCallbacks.get(i).enterDesktop(displayId); } break; + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java index e582a01ea88b..dbcda418496e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiIcons.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.connectivity; +import static com.android.settingslib.flags.Flags.newStatusBarIcons; + import com.android.settingslib.AccessibilityContentDescriptions; import com.android.settingslib.R; import com.android.settingslib.SignalIcon.IconGroup; @@ -23,21 +25,52 @@ import com.android.settingslib.SignalIcon.IconGroup; /** */ public class WifiIcons { - public static final int[] WIFI_FULL_ICONS = { - com.android.internal.R.drawable.ic_wifi_signal_0, - com.android.internal.R.drawable.ic_wifi_signal_1, - com.android.internal.R.drawable.ic_wifi_signal_2, - com.android.internal.R.drawable.ic_wifi_signal_3, - com.android.internal.R.drawable.ic_wifi_signal_4 - }; + public static final int[] WIFI_FULL_ICONS = getIconsBasedOnFlag(); - public static final int[] WIFI_NO_INTERNET_ICONS = { - R.drawable.ic_no_internet_wifi_signal_0, - R.drawable.ic_no_internet_wifi_signal_1, - R.drawable.ic_no_internet_wifi_signal_2, - R.drawable.ic_no_internet_wifi_signal_3, - R.drawable.ic_no_internet_wifi_signal_4 - }; + /** + * Check the aconfig flag to decide on which icons to use. Can be removed once the flag is gone + */ + private static int[] getIconsBasedOnFlag() { + if (newStatusBarIcons()) { + return new int[] { + R.drawable.ic_wifi_0, + R.drawable.ic_wifi_1, + R.drawable.ic_wifi_2, + R.drawable.ic_wifi_3, + R.drawable.ic_wifi_4 + }; + } else { + return new int[] { + com.android.internal.R.drawable.ic_wifi_signal_0, + com.android.internal.R.drawable.ic_wifi_signal_1, + com.android.internal.R.drawable.ic_wifi_signal_2, + com.android.internal.R.drawable.ic_wifi_signal_3, + com.android.internal.R.drawable.ic_wifi_signal_4 + }; + } + } + + public static final int[] WIFI_NO_INTERNET_ICONS = getErrorIconsBasedOnFlag(); + + private static int [] getErrorIconsBasedOnFlag() { + if (newStatusBarIcons()) { + return new int[] { + R.drawable.ic_wifi_0_error, + R.drawable.ic_wifi_1_error, + R.drawable.ic_wifi_2_error, + R.drawable.ic_wifi_3_error, + R.drawable.ic_wifi_4_error + }; + } else { + return new int[] { + R.drawable.ic_no_internet_wifi_signal_0, + R.drawable.ic_no_internet_wifi_signal_1, + R.drawable.ic_no_internet_wifi_signal_2, + R.drawable.ic_no_internet_wifi_signal_3, + R.drawable.ic_no_internet_wifi_signal_4 + }; + } + } public static final int[][] QS_WIFI_SIGNAL_STRENGTH = { WIFI_NO_INTERNET_ICONS, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt index 599600d61976..0fd05550dbe3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt @@ -39,7 +39,6 @@ import android.view.ViewGroup import com.android.keyguard.KeyguardUpdateMonitor import com.android.settingslib.Utils import com.android.systemui.Dumpable -import com.android.systemui.res.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main @@ -54,6 +53,7 @@ import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.clocks.WeatherData import com.android.systemui.plugins.statusbar.StatusBarStateController +import com.android.systemui.res.R import com.android.systemui.settings.UserTracker import com.android.systemui.shared.regionsampling.RegionSampler import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DATE_SMARTSPACE_DATA_PLUGIN @@ -68,11 +68,14 @@ import com.android.systemui.util.settings.SecureSettings import com.android.systemui.util.time.SystemClock import java.io.PrintWriter import java.time.Instant +import java.util.Deque +import java.util.LinkedList import java.util.Optional import java.util.concurrent.Executor import javax.inject.Inject import javax.inject.Named + /** Controller for managing the smartspace view on the lockscreen */ @SysUISingleton class LockscreenSmartspaceController @@ -106,6 +109,8 @@ constructor( ) : Dumpable { companion object { private const val TAG = "LockscreenSmartspaceController" + + private const val MAX_RECENT_SMARTSPACE_DATA_FOR_DUMP = 5 } private var session: SmartspaceSession? = null @@ -114,6 +119,9 @@ constructor( private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null) private val configPlugin: BcSmartspaceConfigPlugin? = optionalConfigPlugin.orElse(null) + // This stores recently received Smartspace pushes to be included in dumpsys. + private val recentSmartspaceData: Deque<List<SmartspaceTarget>> = LinkedList() + // Smartspace can be used on multiple displays, such as when the user casts their screen private var smartspaceViews = mutableSetOf<SmartspaceView>() private var regionSamplers = @@ -173,6 +181,7 @@ constructor( // The weather data plugin takes unfiltered targets and performs the filtering internally. weatherPlugin?.onTargetsAvailable(targets) + val now = Instant.ofEpochMilli(systemClock.currentTimeMillis()) val weatherTarget = targets.find { t -> t.featureType == SmartspaceTarget.FEATURE_WEATHER && @@ -201,6 +210,14 @@ constructor( } val filteredTargets = targets.filter(::filterSmartspaceTarget) + + synchronized(recentSmartspaceData) { + recentSmartspaceData.offerLast(filteredTargets) + if (recentSmartspaceData.size > MAX_RECENT_SMARTSPACE_DATA_FOR_DUMP) { + recentSmartspaceData.pollFirst() + } + } + plugin?.onTargetsAvailable(filteredTargets) } @@ -588,9 +605,26 @@ constructor( return null } - override fun dump(pw: PrintWriter, args: Array<out String>) = pw.asIndenting().run { - printCollection("Region Samplers", regionSamplers.values) { - it.dump(this) + override fun dump(pw: PrintWriter, args: Array<out String>) { + pw.asIndenting().run { + printCollection("Region Samplers", regionSamplers.values) { + it.dump(this) + } + } + + pw.println("Recent BC Smartspace Targets (most recent first)") + synchronized(recentSmartspaceData) { + if (recentSmartspaceData.size === 0) { + pw.println(" No data\n") + return + } + recentSmartspaceData.descendingIterator().forEachRemaining { smartspaceTargets -> + pw.println(" Number of targets: ${smartspaceTargets.size}") + for (target in smartspaceTargets) { + pw.println(" $target") + } + pw.println() + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt index c416d434a8fb..0f0ab2e36b8d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt @@ -108,7 +108,7 @@ constructor( fun trim() { if (events.size > maxEventsPerFrame) { - events.removeFirst() + events.removeAt(0) trimmedEvents++ } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinator.kt index 12de339871bb..4a7b7ca51ba2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinator.kt @@ -54,7 +54,7 @@ class RowAlertTimeCoordinator @Inject constructor() : Coordinator { } private fun GroupEntry.calculateLatestAlertTime(): Long { - val lastChildAlertedTime = children.maxOf { it.lastAudiblyAlertedMs } + val lastChildAlertedTime = children.maxOfOrNull { it.lastAudiblyAlertedMs } ?: 0 val summaryAlertedTime = checkNotNull(summary).lastAudiblyAlertedMs return max(lastChildAlertedTime, summaryAlertedTime) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java index 510086d4892b..dc9eeb35565a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java @@ -191,11 +191,11 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter public boolean shouldBubbleUp(NotificationEntry entry) { final StatusBarNotification sbn = entry.getSbn(); - if (!canAlertCommon(entry, true)) { + if (!canAlertCommon(entry, false)) { return false; } - if (!canAlertAwakeCommon(entry, true)) { + if (!canAlertAwakeCommon(entry, false)) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/SceneContainerFlagsExtension.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/SceneContainerFlagsExtension.kt index 5a71bd6fa116..7dfd53e544c0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/SceneContainerFlagsExtension.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/SceneContainerFlagsExtension.kt @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification.stack.shared import com.android.systemui.scene.shared.flag.SceneContainerFlags -private const val FLEXI_NOTIFS = false +private const val FLEXI_NOTIFS = true /** * Returns whether flexiglass is displaying notifications, which is currently an optional piece of diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt index 052e35c44bbe..b4c88c5f9e79 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt @@ -79,6 +79,7 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.transformWhile import kotlinx.coroutines.isActive /** View-model for the shared notification container, used by both the shade and keyguard spaces */ @@ -89,7 +90,7 @@ constructor( private val interactor: SharedNotificationContainerInteractor, @Application applicationScope: CoroutineScope, private val keyguardInteractor: KeyguardInteractor, - keyguardTransitionInteractor: KeyguardTransitionInteractor, + private val keyguardTransitionInteractor: KeyguardTransitionInteractor, private val shadeInteractor: ShadeInteractor, communalInteractor: CommunalInteractor, private val alternateBouncerToGoneTransitionViewModel: @@ -222,19 +223,60 @@ constructor( initialValue = false, ) + /** + * Fade in if the user swipes the shade back up, not if collapsed by going to AOD. This is + * needed due to the lack of a SHADE state with existing keyguard transitions. + */ + private fun awaitCollapse(): Flow<Boolean> { + var aodTransitionIsComplete = true + return combine( + isOnLockscreenWithoutShade, + keyguardTransitionInteractor + .isInTransitionWhere( + fromStatePredicate = { it == LOCKSCREEN }, + toStatePredicate = { it == AOD } + ) + .onStart { emit(false) }, + ::Pair + ) + .transformWhile { (isOnLockscreenWithoutShade, aodTransitionIsRunning) -> + // Wait until the AOD transition is complete before terminating + if (!aodTransitionIsComplete && !aodTransitionIsRunning) { + aodTransitionIsComplete = true + emit(false) // do not fade in + false + } else if (aodTransitionIsRunning) { + aodTransitionIsComplete = false + true + } else if (isOnLockscreenWithoutShade) { + // Shade is closed, fade in and terminate + emit(true) + false + } else { + true + } + } + } + /** Fade in only for use after the shade collapses */ val shadeCollapseFadeIn: Flow<Boolean> = flow { while (currentCoroutineContext().isActive) { + // Ensure shade is collapsed + isShadeLocked.first { !it } emit(false) // Wait for shade to be fully expanded isShadeLocked.first { it } - // ... and then for it to be collapsed - isOnLockscreenWithoutShade.first { it } - emit(true) - // ... and then for the animation to complete - shadeCollapseFadeInComplete.first { it } - shadeCollapseFadeInComplete.value = false + // ... and then for it to be collapsed OR a transition to AOD begins. + // If AOD, do not fade in (a fade out occurs instead). + awaitCollapse().collect { doFadeIn -> + if (doFadeIn) { + emit(true) + // ... and then for the animation to complete + shadeCollapseFadeInComplete.first { it } + shadeCollapseFadeInComplete.value = false + } + } } } .stateIn( @@ -333,7 +375,7 @@ constructor( lockscreenToPrimaryBouncerTransitionViewModel.lockscreenAlpha, occludedToAodTransitionViewModel.lockscreenAlpha, occludedToLockscreenTransitionViewModel.lockscreenAlpha, - primaryBouncerToGoneTransitionViewModel.lockscreenAlpha, + primaryBouncerToGoneTransitionViewModel.notificationAlpha, primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index 9052409b4d8d..a1fae03a2090 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -39,11 +39,11 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.AuthKeyguardMessageArea; import com.android.systemui.Dumpable; import com.android.systemui.animation.ActivityTransitionAnimator; +import com.android.systemui.animation.RemoteAnimationRunnerCompat; import com.android.systemui.display.data.repository.DisplayMetricsRepository; import com.android.systemui.navigationbar.NavigationBarView; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.qs.QSPanelController; -import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.util.Compile; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java index 6f992ac815cb..d513f8da06e5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java @@ -15,10 +15,12 @@ package com.android.systemui.statusbar.phone; import static com.android.systemui.plugins.DarkIconDispatcher.getTint; +import static com.android.settingslib.flags.Flags.newStatusBarIcons; import android.animation.ArgbEvaluator; import android.content.Context; import android.content.res.ColorStateList; +import android.graphics.Color; import android.graphics.Rect; import android.util.ArrayMap; import android.widget.ImageView; @@ -66,10 +68,16 @@ public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher, Context context, LightBarTransitionsController.Factory lightBarTransitionsControllerFactory, DumpManager dumpManager) { - mDarkModeIconColorSingleTone = context.getColor( - com.android.settingslib.R.color.dark_mode_icon_color_single_tone); - mLightModeIconColorSingleTone = context.getColor( - com.android.settingslib.R.color.light_mode_icon_color_single_tone); + + if (newStatusBarIcons()) { + mDarkModeIconColorSingleTone = Color.BLACK; + mLightModeIconColorSingleTone = Color.WHITE; + } else { + mDarkModeIconColorSingleTone = context.getColor( + com.android.settingslib.R.color.dark_mode_icon_color_single_tone); + mLightModeIconColorSingleTone = context.getColor( + com.android.settingslib.R.color.light_mode_icon_color_single_tone); + } mTransitionsController = lightBarTransitionsControllerFactory.create(this); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java index b07ba3c5b326..a155e94584e3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java @@ -67,7 +67,7 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements OnHeadsUp private static final String TAG = "HeadsUpManagerPhone"; @VisibleForTesting - final int mExtensionTime; + public final int mExtensionTime; private final KeyguardBypassController mBypassController; private final GroupMembershipManager mGroupMembershipManager; private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 5a8b636e54fc..d975009017e3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; import android.app.ActivityTaskManager; import android.app.AlarmManager; import android.app.AlarmManager.AlarmClockInfo; +import android.app.NotificationManager; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; import android.content.Context; @@ -379,7 +380,7 @@ public class PhoneStatusBarPolicy } @Override - public void onConfigChanged(ZenModeConfig config) { + public void onConsolidatedPolicyChanged(NotificationManager.Policy policy) { updateVolumeZen(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt index a608be39f7f7..8f3b0e788dae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository +import android.telephony.CellSignalStrength import android.telephony.SubscriptionInfo import android.telephony.TelephonyManager import com.android.systemui.log.table.TableLogBuffer @@ -149,6 +150,6 @@ interface MobileConnectionRepository { companion object { /** The default number of levels to use for [numberOfLevels]. */ - const val DEFAULT_NUM_LEVELS = 4 + val DEFAULT_NUM_LEVELS = CellSignalStrength.getNumSignalStrengthLevels() } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt index 6de7a00b5a10..3cb138bd75a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt @@ -25,6 +25,7 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionS import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CARRIER_ID import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_CARRIER_NETWORK_CHANGE @@ -223,6 +224,9 @@ class DemoMobileConnectionRepository( _carrierId.value = event.carrierId ?: INVALID_SUBSCRIPTION_ID + numberOfLevels.value = + if (event.inflateStrength) DEFAULT_NUM_LEVELS + 1 else DEFAULT_NUM_LEVELS + cdmaRoaming.value = event.roaming _isRoaming.value = event.roaming // TODO(b/261029387): not yet supported diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSource.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSource.kt index 11a61a9fd319..dbfc576496b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSource.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSource.kt @@ -71,7 +71,7 @@ constructor( val dataType = getString("datatype")?.toDataType() val slot = getString("slot")?.toInt() val carrierId = getString("carrierid")?.toInt() - val inflateStrength = getString("inflate")?.toBoolean() + val inflateStrength = getString("inflate").toBoolean() val activity = getString("activity")?.toActivity() val carrierNetworkChange = getString("carriernetworkchange") == "show" val roaming = getString("roam") == "show" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/model/FakeNetworkEventModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/model/FakeNetworkEventModel.kt index 4836abe73f86..42171d0dc2b5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/model/FakeNetworkEventModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/model/FakeNetworkEventModel.kt @@ -31,7 +31,7 @@ sealed interface FakeNetworkEventModel { // Null means the default (chosen by the repository) val subId: Int?, val carrierId: Int?, - val inflateStrength: Boolean?, + val inflateStrength: Boolean = false, @DataActivityType val activity: Int?, val carrierNetworkChange: Boolean, val roaming: Boolean, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt index 6b303263d4b0..adcf736bba01 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt @@ -69,6 +69,9 @@ interface MobileIconInteractor { /** True if we consider this connection to be in service, i.e. can make calls */ val isInService: StateFlow<Boolean> + /** True if this connection is emergency only */ + val isEmergencyOnly: StateFlow<Boolean> + /** Observable for the data enabled state of this connection */ val isDataEnabled: StateFlow<Boolean> @@ -292,12 +295,7 @@ class MobileIconInteractorImpl( } .stateIn(scope, SharingStarted.WhileSubscribed(), 0) - private val numberOfLevels: StateFlow<Int> = - connectionRepository.numberOfLevels.stateIn( - scope, - SharingStarted.WhileSubscribed(), - connectionRepository.numberOfLevels.value, - ) + private val numberOfLevels: StateFlow<Int> = connectionRepository.numberOfLevels override val isDataConnected: StateFlow<Boolean> = connectionRepository.dataConnectionState @@ -306,6 +304,8 @@ class MobileIconInteractorImpl( override val isInService = connectionRepository.isInService + override val isEmergencyOnly: StateFlow<Boolean> = connectionRepository.isEmergencyOnly + override val isAllowedDuringAirplaneMode = connectionRepository.isAllowedDuringAirplaneMode /** Whether or not to show the error state of [SignalDrawable] */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt index 900a92052153..fd5ab135a1ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt @@ -19,6 +19,8 @@ package com.android.systemui.statusbar.pipeline.mobile.ui.view import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater +import android.widget.ImageView +import com.android.settingslib.flags.Flags.newStatusBarIcons import com.android.systemui.res.R import com.android.systemui.statusbar.StatusBarIconView.getVisibleStateString import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger @@ -59,6 +61,18 @@ class ModernStatusBarMobileView( .inflate(R.layout.status_bar_mobile_signal_group_new, null) as ModernStatusBarMobileView) .also { + // Flag-specific configuration + if (newStatusBarIcons()) { + // New icon (with no embedded whitespace) is slightly shorter + // (but actually taller) + val iconView = it.requireViewById<ImageView>(R.id.mobile_signal) + val lp = iconView.layoutParams + lp.height = + context.resources.getDimensionPixelSize( + R.dimen.status_bar_mobile_signal_size_updated + ) + } + it.subId = viewModel.subscriptionId it.initView(slot) { MobileIconBinder.bind(view = it, viewModel = viewModel, logger = logger) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt index 6e1114c57e87..3f89d04bf492 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt @@ -72,9 +72,16 @@ constructor( /** When all connections are considered OOS, satellite connectivity is potentially valid */ val areAllConnectionsOutOfService = if (Flags.oemEnabledSatelliteFlag()) { - iconsInteractor.icons.aggregateOver(selector = { intr -> intr.isInService }) { - isInServiceList -> - isInServiceList.all { !it } + iconsInteractor.icons.aggregateOver( + selector = { intr -> + combine(intr.isInService, intr.isEmergencyOnly) { + isInService, + isEmergencyOnly -> + !isInService && !isEmergencyOnly + } + } + ) { isOosAndIsNotEmergencyOnly -> + isOosAndIsNotEmergencyOnly.all { it } } } else { flowOf(false) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt index 4cd348412f63..ba55aadace0a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt @@ -20,6 +20,9 @@ import android.annotation.SuppressLint import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.ImageView +import com.android.settingslib.flags.Flags.newStatusBarIcons import com.android.systemui.res.R import com.android.systemui.statusbar.StatusBarIconView import com.android.systemui.statusbar.pipeline.shared.ui.view.ModernStatusBarView @@ -57,7 +60,18 @@ class ModernStatusBarWifiView( ): ModernStatusBarWifiView { return (LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null) as ModernStatusBarWifiView) - .also { it.initView(slot) { WifiViewBinder.bind(it, wifiViewModel) } } + .also { + // Flag-specific configuration + if (newStatusBarIcons()) { + // The newer asset does not embed whitespace around it, and is therefore + // rectangular. Use wrap_content for the width in this case + val iconView = it.requireViewById<ImageView>(R.id.wifi_signal) + val lp = iconView.layoutParams + lp.width = ViewGroup.LayoutParams.WRAP_CONTENT + } + + it.initView(slot) { WifiViewBinder.bind(it, wifiViewModel) } + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt index 5c53ff98b777..d19a3364d502 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldLightRevealOverlayAnimation.kt @@ -16,6 +16,8 @@ package com.android.systemui.unfold +import android.animation.Animator +import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.annotation.BinderThread import android.content.Context @@ -23,7 +25,6 @@ import android.os.Handler import android.os.SystemProperties import android.util.Log import android.view.animation.DecelerateInterpolator -import androidx.core.animation.addListener import com.android.internal.foldables.FoldLockSettingAvailabilityProvider import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.display.data.repository.DeviceStateRepository @@ -36,17 +37,25 @@ import com.android.systemui.unfold.FullscreenLightRevealAnimationController.Comp import com.android.systemui.unfold.dagger.UnfoldBg import com.android.systemui.util.animation.data.repository.AnimationStatusRepository import javax.inject.Inject +import kotlin.coroutines.resume import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.TimeoutCancellationException import kotlinx.coroutines.android.asCoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withTimeout +@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) class FoldLightRevealOverlayAnimation @Inject constructor( @@ -61,6 +70,9 @@ constructor( private val revealProgressValueAnimator: ValueAnimator = ValueAnimator.ofFloat(ALPHA_OPAQUE, ALPHA_TRANSPARENT) + private val areAnimationEnabled: Flow<Boolean> + get() = animationStatusRepository.areAnimationsEnabled() + private lateinit var controller: FullscreenLightRevealAnimationController @Volatile private var readyCallback: CompletableDeferred<Runnable>? = null @@ -89,33 +101,30 @@ constructor( applicationScope.launch(bgHandler.asCoroutineDispatcher()) { deviceStateRepository.state - .map { it != DeviceStateRepository.DeviceState.FOLDED } + .map { it == DeviceStateRepository.DeviceState.FOLDED } .distinctUntilChanged() - .filter { isUnfolded -> isUnfolded } - .collect { controller.ensureOverlayRemoved() } - } - - applicationScope.launch(bgHandler.asCoroutineDispatcher()) { - deviceStateRepository.state - .filter { - animationStatusRepository.areAnimationsEnabled().first() && - it == DeviceStateRepository.DeviceState.FOLDED - } - .collect { - try { - withTimeout(WAIT_FOR_ANIMATION_TIMEOUT_MS) { - readyCallback = CompletableDeferred() - val onReady = readyCallback?.await() - readyCallback = null - controller.addOverlay(ALPHA_OPAQUE, onReady) - waitForScreenTurnedOn() + .flatMapLatest { isFolded -> + flow<Nothing> { + if (!areAnimationEnabled.first() || !isFolded) { + return@flow + } + withTimeout(WAIT_FOR_ANIMATION_TIMEOUT_MS) { + readyCallback = CompletableDeferred() + val onReady = readyCallback?.await() + readyCallback = null + controller.addOverlay(ALPHA_OPAQUE, onReady) + waitForScreenTurnedOn() + } playFoldLightRevealOverlayAnimation() } - } catch (e: TimeoutCancellationException) { - Log.e(TAG, "Fold light reveal animation timed out") - ensureOverlayRemovedInternal() - } + .catchTimeoutAndLog() + .onCompletion { + val onReady = readyCallback?.takeIf { it.isCompleted }?.getCompleted() + onReady?.run() + readyCallback = null + } } + .collect {} } } @@ -128,19 +137,34 @@ constructor( powerInteractor.screenPowerState.filter { it == ScreenPowerState.SCREEN_ON }.first() } - private fun ensureOverlayRemovedInternal() { - revealProgressValueAnimator.cancel() - controller.ensureOverlayRemoved() - } - - private fun playFoldLightRevealOverlayAnimation() { + private suspend fun playFoldLightRevealOverlayAnimation() { revealProgressValueAnimator.duration = ANIMATION_DURATION revealProgressValueAnimator.interpolator = DecelerateInterpolator() revealProgressValueAnimator.addUpdateListener { animation -> controller.updateRevealAmount(animation.animatedFraction) } - revealProgressValueAnimator.addListener(onEnd = { controller.ensureOverlayRemoved() }) - revealProgressValueAnimator.start() + revealProgressValueAnimator.startAndAwaitCompletion() + } + + private suspend fun ValueAnimator.startAndAwaitCompletion(): Unit = + suspendCancellableCoroutine { continuation -> + val listener = + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + continuation.resume(Unit) + removeListener(this) + } + } + addListener(listener) + continuation.invokeOnCancellation { removeListener(listener) } + start() + } + + private fun <T> Flow<T>.catchTimeoutAndLog() = catch { exception -> + when (exception) { + is TimeoutCancellationException -> Log.e(TAG, "Fold light reveal animation timed out") + else -> throw exception + } } private companion object { diff --git a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java index 3d724e1caa5d..0dcbe9b2bfc4 100644 --- a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java +++ b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java @@ -158,11 +158,11 @@ public class ObservableServiceConnection<T> implements ServiceConnection { try { bindResult = mContext.bindServiceAsUser(mServiceIntent, this, mFlags, mUserTracker.getUserHandle()); + mBoundCalled = true; } catch (SecurityException e) { Log.d(TAG, "Could not bind to service", e); mContext.unbindService(this); } - mBoundCalled = true; if (DEBUG) { Log.d(TAG, "bind. bound:" + bindResult); } diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/ClientTrackingWakeLock.kt b/packages/SystemUI/src/com/android/systemui/util/wakelock/ClientTrackingWakeLock.kt new file mode 100644 index 000000000000..db300ebe6cae --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/ClientTrackingWakeLock.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.util.wakelock + +import android.os.PowerManager +import android.util.Log +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.atomic.AtomicInteger + +/** + * [PowerManager.WakeLock] wrapper that tracks acquire/release reasons and logs them if owning + * logger is enabled. + */ +class ClientTrackingWakeLock( + private val pmWakeLock: PowerManager.WakeLock, + private val logger: WakeLockLogger?, + private val maxTimeout: Long +) : WakeLock { + + private val activeClients = ConcurrentHashMap<String, AtomicInteger>() + + override fun acquire(why: String) { + val count = activeClients.computeIfAbsent(why) { _ -> AtomicInteger(0) }.incrementAndGet() + logger?.logAcquire(pmWakeLock, why, count) + pmWakeLock.acquire(maxTimeout) + } + + override fun release(why: String) { + val count = activeClients[why]?.decrementAndGet() ?: -1 + if (count < 0) { + Log.wtf(WakeLock.TAG, "Releasing WakeLock with invalid reason: $why") + // Restore count just in case. + activeClients[why]?.incrementAndGet() + return + } + + logger?.logRelease(pmWakeLock, why, count) + pmWakeLock.release() + } + + override fun wrap(r: Runnable): Runnable = WakeLock.wrapImpl(this, r) + + fun activeClients(): Int = + activeClients.reduceValuesToInt(Long.MAX_VALUE, AtomicInteger::get, 0, Integer::sum) + + override fun toString(): String { + return "active clients=${activeClients()}" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java index 039109e9ddc6..d2ed71cc3af1 100644 --- a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java +++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java @@ -19,8 +19,11 @@ package com.android.systemui.util.wakelock; import android.content.Context; import android.os.Handler; +import com.android.systemui.Flags; import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import dagger.Lazy; import dagger.assisted.Assisted; import dagger.assisted.AssistedFactory; import dagger.assisted.AssistedInject; @@ -37,10 +40,13 @@ public class DelayedWakeLock implements WakeLock { private final WakeLock mInner; @AssistedInject - public DelayedWakeLock(@Background Handler handler, Context context, WakeLockLogger logger, + public DelayedWakeLock(@Background Lazy<Handler> bgHandler, + @Main Lazy<Handler> mainHandler, + Context context, WakeLockLogger logger, @Assisted String tag) { mInner = WakeLock.createPartial(context, logger, tag); - mHandler = handler; + mHandler = Flags.delayedWakelockReleaseOnBackgroundThread() ? bgHandler.get() + : mainHandler.get(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java index 6128feee8116..707751a58d84 100644 --- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java +++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java @@ -22,6 +22,8 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; +import com.android.systemui.Flags; + import java.util.HashMap; import javax.inject.Inject; @@ -112,6 +114,11 @@ public interface WakeLock { @VisibleForTesting static WakeLock wrap( final PowerManager.WakeLock inner, WakeLockLogger logger, long maxTimeout) { + if (Flags.delayedWakelockReleaseOnBackgroundThread()) { + return new ClientTrackingWakeLock(inner, logger, maxTimeout); + } + + // Non-thread safe implementation, remove when flag above is removed. return new WakeLock() { private final HashMap<String, Integer> mActiveClients = new HashMap<>(); diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt index 8431fbcd8bad..9dedf5c70da1 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt @@ -18,9 +18,6 @@ package com.android.systemui.volume.dagger import android.content.Context import android.media.AudioManager -import com.android.settingslib.media.data.repository.SpatializerRepository -import com.android.settingslib.media.data.repository.SpatializerRepositoryImpl -import com.android.settingslib.media.domain.interactor.SpatializerInteractor import com.android.settingslib.statusbar.notification.domain.interactor.NotificationsSoundPolicyInteractor import com.android.settingslib.volume.data.repository.AudioRepository import com.android.settingslib.volume.data.repository.AudioRepositoryImpl @@ -66,16 +63,5 @@ interface AudioModule { notificationsSoundPolicyInteractor: NotificationsSoundPolicyInteractor, ): AudioVolumeInteractor = AudioVolumeInteractor(audioRepository, notificationsSoundPolicyInteractor) - - @Provides - fun provdieSpatializerRepository( - audioManager: AudioManager, - @Background backgroundContext: CoroutineContext, - ): SpatializerRepository = - SpatializerRepositoryImpl(audioManager.spatializer, backgroundContext) - - @Provides - fun provideSpatializerInetractor(repository: SpatializerRepository): SpatializerInteractor = - SpatializerInteractor(repository) } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/SpatializerModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/SpatializerModule.kt new file mode 100644 index 000000000000..593b90aa3c68 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/SpatializerModule.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.dagger + +import android.media.AudioManager +import android.media.Spatializer +import com.android.settingslib.media.data.repository.SpatializerRepository +import com.android.settingslib.media.data.repository.SpatializerRepositoryImpl +import com.android.settingslib.media.domain.interactor.SpatializerInteractor +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.dagger.qualifiers.Background +import dagger.Module +import dagger.Provides +import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.CoroutineScope + +/** Spatializer module. */ +@Module +interface SpatializerModule { + + companion object { + + @Provides + fun provideSpatializer( + audioManager: AudioManager, + ): Spatializer = audioManager.spatializer + + @Provides + fun provdieSpatializerRepository( + spatializer: Spatializer, + @Application scope: CoroutineScope, + @Background backgroundContext: CoroutineContext, + ): SpatializerRepository = SpatializerRepositoryImpl(spatializer, scope, backgroundContext) + + @Provides + fun provideSpatializerInetractor(repository: SpatializerRepository): SpatializerInteractor = + SpatializerInteractor(repository) + } +} 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 c6aee428ce6a..64a5644bc452 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java +++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java @@ -59,7 +59,8 @@ import dagger.multibindings.IntoSet; AudioModule.class, AncModule.class, CaptioningModule.class, - MediaDevicesModule.class + MediaDevicesModule.class, + SpatializerModule.class, }, subcomponents = { VolumePanelComponent.class diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteria.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteria.kt new file mode 100644 index 000000000000..71bce5e470f4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteria.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.spatial.domain + +import com.android.systemui.volume.panel.component.spatial.domain.interactor.SpatialAudioComponentInteractor +import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel +import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope +import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +@VolumePanelScope +class SpatialAudioAvailabilityCriteria +@Inject +constructor(private val interactor: SpatialAudioComponentInteractor) : + ComponentAvailabilityCriteria { + + override fun isAvailable(): Flow<Boolean> = + interactor.isAvailable.map { it is SpatialAudioAvailabilityModel.SpatialAudio } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt new file mode 100644 index 000000000000..4358611694b2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.spatial.domain.interactor + +import android.media.AudioDeviceAttributes +import android.media.AudioDeviceInfo +import com.android.settingslib.bluetooth.CachedBluetoothDevice +import com.android.settingslib.media.BluetoothMediaDevice +import com.android.settingslib.media.domain.interactor.SpatializerInteractor +import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor +import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel +import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel +import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn + +/** + * Provides an ability to access and update spatial audio and head tracking state. + * + * Head tracking is a sub-feature of spatial audio. This means that it requires spatial audio to be + * available for it to be available. And spatial audio to be enabled for it to be enabled. + */ +@VolumePanelScope +class SpatialAudioComponentInteractor +@Inject +constructor( + mediaOutputInteractor: MediaOutputInteractor, + private val spatializerInteractor: SpatializerInteractor, + @VolumePanelScope private val coroutineScope: CoroutineScope, +) { + + private val changes = MutableSharedFlow<Unit>() + private val currentAudioDeviceAttributes: StateFlow<AudioDeviceAttributes?> = + mediaOutputInteractor.currentConnectedDevice + .map { mediaDevice -> + mediaDevice ?: return@map null + val btDevice: CachedBluetoothDevice = + (mediaDevice as? BluetoothMediaDevice)?.cachedDevice ?: return@map null + btDevice.getAudioDeviceAttributes() + } + .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), null) + + /** + * Returns spatial audio availability model. It can be: + * - unavailable + * - only spatial audio is available + * - spatial audio and head tracking are available + */ + val isAvailable: StateFlow<SpatialAudioAvailabilityModel> = + combine( + currentAudioDeviceAttributes, + changes.onStart { emit(Unit) }, + spatializerInteractor.isHeadTrackingAvailable, + ) { attributes, _, isHeadTrackingAvailable -> + attributes ?: return@combine SpatialAudioAvailabilityModel.Unavailable + if (isHeadTrackingAvailable) { + return@combine SpatialAudioAvailabilityModel.HeadTracking + } + if (spatializerInteractor.isSpatialAudioAvailable(attributes)) { + return@combine SpatialAudioAvailabilityModel.SpatialAudio + } + SpatialAudioAvailabilityModel.Unavailable + } + .stateIn( + coroutineScope, + SharingStarted.Eagerly, + SpatialAudioAvailabilityModel.Unavailable, + ) + + /** + * Returns spatial audio enabled/disabled model. It can be + * - disabled + * - only spatial audio is enabled + * - spatial audio and head tracking are enabled + */ + val isEnabled: StateFlow<SpatialAudioEnabledModel> = + combine( + changes.onStart { emit(Unit) }, + currentAudioDeviceAttributes, + isAvailable, + ) { _, attributes, isAvailable -> + if (isAvailable is SpatialAudioAvailabilityModel.Unavailable) { + return@combine SpatialAudioEnabledModel.Disabled + } + attributes ?: return@combine SpatialAudioEnabledModel.Disabled + if (spatializerInteractor.isHeadTrackingEnabled(attributes)) { + return@combine SpatialAudioEnabledModel.HeadTrackingEnabled + } + if (spatializerInteractor.isSpatialAudioEnabled(attributes)) { + return@combine SpatialAudioEnabledModel.SpatialAudioEnabled + } + SpatialAudioEnabledModel.Disabled + } + .stateIn( + coroutineScope, + SharingStarted.Eagerly, + SpatialAudioEnabledModel.Disabled, + ) + + /** + * Sets current [isEnabled] to a specific [SpatialAudioEnabledModel]. It + * - disables both spatial audio and head tracking + * - enables only spatial audio + * - enables both spatial audio and head tracking + */ + suspend fun setEnabled(model: SpatialAudioEnabledModel) { + val attributes = currentAudioDeviceAttributes.value ?: return + spatializerInteractor.setSpatialAudioEnabled( + attributes, + model is SpatialAudioEnabledModel.SpatialAudioEnabled, + ) + spatializerInteractor.setHeadTrackingEnabled( + attributes, + model is SpatialAudioEnabledModel.HeadTrackingEnabled, + ) + changes.emit(Unit) + } + + private suspend fun CachedBluetoothDevice.getAudioDeviceAttributes(): AudioDeviceAttributes? { + return listOf( + AudioDeviceAttributes( + AudioDeviceAttributes.ROLE_OUTPUT, + AudioDeviceInfo.TYPE_BLE_HEADSET, + address + ), + AudioDeviceAttributes( + AudioDeviceAttributes.ROLE_OUTPUT, + AudioDeviceInfo.TYPE_BLE_SPEAKER, + address + ), + AudioDeviceAttributes( + AudioDeviceAttributes.ROLE_OUTPUT, + AudioDeviceInfo.TYPE_BLE_BROADCAST, + address + ), + AudioDeviceAttributes( + AudioDeviceAttributes.ROLE_OUTPUT, + AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, + address + ), + AudioDeviceAttributes( + AudioDeviceAttributes.ROLE_OUTPUT, + AudioDeviceInfo.TYPE_HEARING_AID, + address + ) + ) + .firstOrNull { spatializerInteractor.isSpatialAudioAvailable(it) } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioAvailabilityModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioAvailabilityModel.kt new file mode 100644 index 000000000000..cf1454618367 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioAvailabilityModel.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.spatial.domain.model + +/** Models spatial audio and head tracking availability. */ +interface SpatialAudioAvailabilityModel { + + /** Spatial audio is unavailable. */ + data object Unavailable : SpatialAudioAvailabilityModel + + /** Spatial audio is available. */ + interface SpatialAudio : SpatialAudioAvailabilityModel { + companion object : SpatialAudio + } + + /** Head tracking is available. This also means that [SpatialAudio] is available. */ + data object HeadTracking : SpatialAudio +} diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioEnabledModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioEnabledModel.kt new file mode 100644 index 000000000000..4e65f60aa0e1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioEnabledModel.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.spatial.domain.model + +/** Models spatial audio and head tracking enabled/disabled state. */ +interface SpatialAudioEnabledModel { + + /** Spatial audio is disabled. */ + data object Disabled : SpatialAudioEnabledModel + + /** Spatial audio is enabled. */ + interface SpatialAudioEnabled : SpatialAudioEnabledModel { + companion object : SpatialAudioEnabled + } + + /** Head tracking is enabled. This also means that [SpatialAudioEnabled]. */ + data object HeadTrackingEnabled : SpatialAudioEnabled +} diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java index f498520f219b..1a399341f12c 100644 --- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java +++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java @@ -20,6 +20,7 @@ import static com.android.systemui.wallet.ui.WalletCardCarousel.CARD_ANIM_ALPHA_ import static com.android.systemui.wallet.ui.WalletCardCarousel.CARD_ANIM_ALPHA_DURATION; import android.annotation.Nullable; +import android.app.ActivityOptions; import android.app.BroadcastOptions; import android.app.PendingIntent; import android.content.Context; @@ -40,8 +41,8 @@ import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; import com.android.settingslib.Utils; -import com.android.systemui.res.R; import com.android.systemui.classifier.FalsingCollector; +import com.android.systemui.res.R; import java.util.List; @@ -308,7 +309,7 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard BroadcastOptions options = BroadcastOptions.makeBasic(); options.setInteractive(true); options.setPendingIntentBackgroundActivityStartMode( - BroadcastOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED); + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED); walletCard.getPendingIntent().send(options.toBundle()); } catch (PendingIntent.CanceledException e) { Log.w(TAG, "Error sending pending intent for wallet card."); diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index 15e0965c16fe..324d723207cd 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -256,7 +256,7 @@ public final class WMShell implements }); mCommandQueue.addCallback(new CommandQueue.Callbacks() { @Override - public void goToFullscreenFromSplit() { + public void moveFocusedTaskToFullscreen(int displayId) { splitScreen.goToFullscreenFromSplit(); } }); @@ -362,6 +362,12 @@ public final class WMShell implements desktopMode.enterDesktop(displayId); } }); + mCommandQueue.addCallback(new CommandQueue.Callbacks() { + @Override + public void moveFocusedTaskToFullscreen(int displayId) { + desktopMode.moveFocusedTaskToFullscreen(displayId); + } + }); } @VisibleForTesting diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt index 30269664a559..0f8a81399be8 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -336,48 +336,6 @@ class ClockEventControllerTest : SysuiTestCase() { } @Test - fun listenForTransitionToAodFromGone_updatesClockDozeAmountToOne() = - runBlocking(IMMEDIATE) { - val transitionStep = MutableStateFlow(TransitionStep()) - whenever(keyguardTransitionInteractor.transitionStepsToState(KeyguardState.AOD)) - .thenReturn(transitionStep) - - val job = underTest.listenForAnyStateToAodTransition(this) - transitionStep.value = - TransitionStep( - from = KeyguardState.GONE, - to = KeyguardState.AOD, - transitionState = TransitionState.STARTED, - ) - yield() - - verify(animations, times(2)).doze(1f) - - job.cancel() - } - - @Test - fun listenForTransitionToAodFromLockscreen_neverUpdatesClockDozeAmount() = - runBlocking(IMMEDIATE) { - val transitionStep = MutableStateFlow(TransitionStep()) - whenever(keyguardTransitionInteractor.transitionStepsToState(KeyguardState.AOD)) - .thenReturn(transitionStep) - - val job = underTest.listenForAnyStateToAodTransition(this) - transitionStep.value = - TransitionStep( - from = KeyguardState.LOCKSCREEN, - to = KeyguardState.AOD, - transitionState = TransitionState.STARTED, - ) - yield() - - verify(animations, never()).doze(1f) - - job.cancel() - } - - @Test fun unregisterListeners_validate() = runBlocking(IMMEDIATE) { underTest.unregisterListeners() diff --git a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt index 4ab7ab450fae..043dcaa0d919 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt @@ -15,10 +15,13 @@ */ package com.android.systemui.battery +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.widget.ImageView import androidx.test.filters.SmallTest +import com.android.settingslib.flags.Flags.FLAG_NEW_STATUS_BAR_ICONS import com.android.systemui.res.R import com.android.systemui.SysuiTestCase import com.android.systemui.battery.BatteryMeterView.BatteryEstimateFetcher @@ -141,7 +144,8 @@ class BatteryMeterViewTest : SysuiTestCase() { } @Test - fun changesFromEstimateToPercent_textAndContentDescriptionChanges() { + @DisableFlags(FLAG_NEW_STATUS_BAR_ICONS) + fun changesFromEstimateToPercent_textAndContentDescriptionChanges_flagOff() { mBatteryMeterView.onBatteryLevelChanged(15, false) mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE) mBatteryMeterView.setBatteryEstimateFetcher(Fetcher()) @@ -164,6 +168,31 @@ class BatteryMeterViewTest : SysuiTestCase() { } @Test + @EnableFlags(FLAG_NEW_STATUS_BAR_ICONS) + fun changesFromEstimateToPercent_textAndContentDescriptionChanges_flagOn() { + mBatteryMeterView.onBatteryLevelChanged(15, false) + mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE) + mBatteryMeterView.setBatteryEstimateFetcher(Fetcher()) + + mBatteryMeterView.updatePercentText() + + assertThat(mBatteryMeterView.contentDescription).isEqualTo( + context.getString( + R.string.accessibility_battery_level_with_estimate, 15, ESTIMATE + ) + ) + + // Update the show mode from estimate to percent + mBatteryMeterView.setPercentShowMode(BatteryMeterView.MODE_ON) + + assertThat(mBatteryMeterView.batteryPercentView).isNull() + assertThat(mBatteryMeterView.contentDescription).isEqualTo( + context.getString(R.string.accessibility_battery_level, 15) + ) + assertThat(mBatteryMeterView.unifiedBatteryState.showPercent).isTrue() + } + + @Test fun contentDescription_manyUpdates_alwaysUpdated() { // BatteryDefender mBatteryMeterView.onBatteryLevelChanged(90, false) @@ -208,7 +237,8 @@ class BatteryMeterViewTest : SysuiTestCase() { } @Test - fun isBatteryDefenderChanged_true_drawableGetsTrue() { + @DisableFlags(FLAG_NEW_STATUS_BAR_ICONS) + fun isBatteryDefenderChanged_true_drawableGetsTrue_flagOff() { mBatteryMeterView.setDisplayShieldEnabled(true) val drawable = getBatteryDrawable() @@ -218,7 +248,18 @@ class BatteryMeterViewTest : SysuiTestCase() { } @Test - fun isBatteryDefenderChanged_false_drawableGetsFalse() { + @EnableFlags(FLAG_NEW_STATUS_BAR_ICONS) + fun isBatteryDefenderChanged_true_drawableGetsTrue_flagOn() { + mBatteryMeterView.setDisplayShieldEnabled(true) + + mBatteryMeterView.onIsBatteryDefenderChanged(true) + + assertThat(mBatteryMeterView.unifiedBatteryState.attribution).isNotNull() + } + + @Test + @DisableFlags(FLAG_NEW_STATUS_BAR_ICONS) + fun isBatteryDefenderChanged_false_drawableGetsFalse_flagOff() { mBatteryMeterView.setDisplayShieldEnabled(true) val drawable = getBatteryDrawable() @@ -232,7 +273,22 @@ class BatteryMeterViewTest : SysuiTestCase() { } @Test - fun isBatteryDefenderChanged_true_featureflagOff_drawableGetsFalse() { + @EnableFlags(FLAG_NEW_STATUS_BAR_ICONS) + fun isBatteryDefenderChanged_false_drawableGetsFalse_flagOn() { + mBatteryMeterView.setDisplayShieldEnabled(true) + + // Start as true + mBatteryMeterView.onIsBatteryDefenderChanged(true) + + // Update to false + mBatteryMeterView.onIsBatteryDefenderChanged(false) + + assertThat(mBatteryMeterView.unifiedBatteryState.attribution).isNull() + } + + @Test + @DisableFlags(FLAG_NEW_STATUS_BAR_ICONS) + fun isBatteryDefenderChanged_true_featureflagOff_drawableGetsFalse_flagOff() { mBatteryMeterView.setDisplayShieldEnabled(false) val drawable = getBatteryDrawable() @@ -242,17 +298,41 @@ class BatteryMeterViewTest : SysuiTestCase() { } @Test - fun isIncompatibleChargingChanged_true_drawableGetsChargingFalse() { + @EnableFlags(FLAG_NEW_STATUS_BAR_ICONS) + fun isBatteryDefenderChanged_true_featureflagOff_drawableGetsFalse_flagOn() { + mBatteryMeterView.setDisplayShieldEnabled(false) + + mBatteryMeterView.onIsBatteryDefenderChanged(true) + + assertThat(mBatteryMeterView.unifiedBatteryState.attribution).isNull() + } + + @Test + @DisableFlags(FLAG_NEW_STATUS_BAR_ICONS) + fun isIncompatibleChargingChanged_true_drawableGetsChargingFalse_flagOff() { mBatteryMeterView.onBatteryLevelChanged(45, true) val drawable = getBatteryDrawable() mBatteryMeterView.onIsIncompatibleChargingChanged(true) assertThat(drawable.getCharging()).isFalse() + assertThat(mBatteryMeterView.isCharging).isFalse() } @Test - fun isIncompatibleChargingChanged_false_drawableGetsChargingTrue() { + @EnableFlags(FLAG_NEW_STATUS_BAR_ICONS) + fun isIncompatibleChargingChanged_true_drawableGetsChargingFalse_flagOn() { + mBatteryMeterView.onBatteryLevelChanged(45, true) + + mBatteryMeterView.onIsIncompatibleChargingChanged(true) + + assertThat(mBatteryMeterView.unifiedBatteryState.attribution).isNull() + assertThat(mBatteryMeterView.isCharging).isFalse() + } + + @Test + @DisableFlags(FLAG_NEW_STATUS_BAR_ICONS) + fun isIncompatibleChargingChanged_false_drawableGetsChargingTrue_flagOff() { mBatteryMeterView.onBatteryLevelChanged(45, true) val drawable = getBatteryDrawable() @@ -261,6 +341,17 @@ class BatteryMeterViewTest : SysuiTestCase() { assertThat(drawable.getCharging()).isTrue() } + @Test + @EnableFlags(FLAG_NEW_STATUS_BAR_ICONS) + fun isIncompatibleChargingChanged_false_drawableGetsChargingTrue_flagOn() { + mBatteryMeterView.onBatteryLevelChanged(45, true) + + mBatteryMeterView.onIsIncompatibleChargingChanged(false) + + assertThat(mBatteryMeterView.isCharging).isTrue() + assertThat(mBatteryMeterView.unifiedBatteryState.attribution).isNotNull() + } + private fun getBatteryDrawable(): AccessorizedBatteryDrawable { return (mBatteryMeterView.getChildAt(0) as ImageView) .drawable as AccessorizedBatteryDrawable diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt index 9f24d5dfea79..f5e96c93271a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt @@ -237,6 +237,35 @@ class FacePropertyRepositoryImplTest : SysuiTestCase() { } } + @Test + fun providesTheCameraInfoOnCameraAvailableChange() { + testScope.runTest { + runCurrent() + collectLastValue(underTest.cameraInfo) + + verify(faceManager).addAuthenticatorsRegisteredCallback(callback.capture()) + callback.value.onAllAuthenticatorsRegistered( + listOf(createSensorProperties(1, SensorProperties.STRENGTH_STRONG)) + ) + runCurrent() + verify(cameraManager) + .registerAvailabilityCallback(any(Executor::class.java), cameraCallback.capture()) + + cameraCallback.value.onPhysicalCameraAvailable("0", PHYSICAL_CAMERA_ID_OUTER_FRONT) + runCurrent() + + val cameraInfo by collectLastValue(underTest.cameraInfo) + assertThat(cameraInfo) + .isEqualTo( + CameraInfo( + "0", + PHYSICAL_CAMERA_ID_OUTER_FRONT, + Point(OUTER_FRONT_SENSOR_LOCATION[0], OUTER_FRONT_SENSOR_LOCATION[1]) + ) + ) + } + } + private fun createSensorProperties(id: Int, strength: Int) = FaceSensorPropertiesInternal(id, strength, 0, emptyList(), 1, false, false, false) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt index ff68fe3df9e9..140849b8e257 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt @@ -241,19 +241,27 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa viewModel.showAuthenticated(testCase.authenticatedModality, 1_000L) - val confirmConstant by collectLastValue(viewModel.hapticsToPlay) - assertThat(confirmConstant) + val confirmHaptics by collectLastValue(viewModel.hapticsToPlay) + assertThat(confirmHaptics?.hapticFeedbackConstant) .isEqualTo( if (expectConfirmation) HapticFeedbackConstants.NO_HAPTICS else HapticFeedbackConstants.CONFIRM ) + assertThat(confirmHaptics?.flag) + .isEqualTo( + if (expectConfirmation) null + else HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING + ) if (expectConfirmation) { viewModel.confirmAuthenticated() } - val confirmedConstant by collectLastValue(viewModel.hapticsToPlay) - assertThat(confirmedConstant).isEqualTo(HapticFeedbackConstants.CONFIRM) + val confirmedHaptics by collectLastValue(viewModel.hapticsToPlay) + assertThat(confirmedHaptics?.hapticFeedbackConstant) + .isEqualTo(HapticFeedbackConstants.CONFIRM) + assertThat(confirmedHaptics?.flag) + .isEqualTo(HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) } @Test @@ -265,16 +273,21 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa viewModel.confirmAuthenticated() } - val currentConstant by collectLastValue(viewModel.hapticsToPlay) - assertThat(currentConstant).isEqualTo(HapticFeedbackConstants.CONFIRM) + val currentHaptics by collectLastValue(viewModel.hapticsToPlay) + assertThat(currentHaptics?.hapticFeedbackConstant) + .isEqualTo(HapticFeedbackConstants.CONFIRM) + assertThat(currentHaptics?.flag) + .isEqualTo(HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) } @Test fun playErrorHaptic_SetsRejectConstant() = runGenericTest { viewModel.showTemporaryError("test", "messageAfterError", false) - val currentConstant by collectLastValue(viewModel.hapticsToPlay) - assertThat(currentConstant).isEqualTo(HapticFeedbackConstants.REJECT) + val currentHaptics by collectLastValue(viewModel.hapticsToPlay) + assertThat(currentHaptics?.hapticFeedbackConstant).isEqualTo(HapticFeedbackConstants.REJECT) + assertThat(currentHaptics?.flag) + .isEqualTo(HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) } @Test @@ -800,8 +813,9 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa hapticFeedback = true, ) - val constant by collectLastValue(viewModel.hapticsToPlay) - assertThat(constant).isEqualTo(HapticFeedbackConstants.REJECT) + val haptics by collectLastValue(viewModel.hapticsToPlay) + assertThat(haptics?.hapticFeedbackConstant).isEqualTo(HapticFeedbackConstants.REJECT) + assertThat(haptics?.flag).isEqualTo(HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) } @Test @@ -813,8 +827,8 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa hapticFeedback = false, ) - val constant by collectLastValue(viewModel.hapticsToPlay) - assertThat(constant).isEqualTo(HapticFeedbackConstants.NO_HAPTICS) + val haptics by collectLastValue(viewModel.hapticsToPlay) + assertThat(haptics?.hapticFeedbackConstant).isEqualTo(HapticFeedbackConstants.NO_HAPTICS) } private suspend fun TestScope.showTemporaryErrors( diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt index e30dd35d74c1..e1e9fcb2d059 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt @@ -25,6 +25,7 @@ import androidx.test.filters.SmallTest import com.android.keyguard.keyguardUpdateMonitor import com.android.keyguard.trustManager import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.CameraInfo import com.android.systemui.biometrics.data.repository.FaceSensorInfo import com.android.systemui.biometrics.data.repository.facePropertyRepository import com.android.systemui.biometrics.shared.model.LockoutMode @@ -490,6 +491,47 @@ class DeviceEntryFaceAuthInteractorTest : SysuiTestCase() { verify(trustManager).clearAllBiometricRecognized(eq(BiometricSourceType.FACE), anyInt()) } + @Test + fun faceAuthIsRequestedWhenAuthIsRunningWhileCameraInfoChanged() = + testScope.runTest { + facePropertyRepository.setCameraIno(null) + underTest.start() + + faceAuthRepository.requestAuthenticate( + FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED, + true + ) + facePropertyRepository.setCameraIno(CameraInfo("0", "1", null)) + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value) + .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_CAMERA_AVAILABLE_CHANGED, true)) + } + + @Test + fun faceAuthIsNotRequestedWhenNoAuthRunningWhileCameraInfoChanged() = + testScope.runTest { + facePropertyRepository.setCameraIno(null) + underTest.start() + + facePropertyRepository.setCameraIno(CameraInfo("0", "1", null)) + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value).isNull() + } + + @Test + fun faceAuthIsNotRequestedWhenAuthIsRunningWhileCameraInfoIsNull() = + testScope.runTest { + facePropertyRepository.setCameraIno(null) + underTest.start() + + facePropertyRepository.setCameraIno(null) + + runCurrent() + assertThat(faceAuthRepository.runningAuthRequest.value).isNull() + } + companion object { private const val primaryUserId = 1 private val primaryUser = UserInfo(primaryUserId, "test user", UserInfo.FLAG_PRIMARY) diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt index e97edcbdc68a..9b8cf592d496 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt @@ -27,7 +27,7 @@ import com.android.systemui.deviceentry.data.ui.viewmodel.deviceEntryUdfpsAccess import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository -import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState @@ -39,6 +39,7 @@ import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlin.test.Test import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.runner.RunWith @@ -52,7 +53,7 @@ class UdfpsAccessibilityOverlayViewModelTest : SysuiTestCase() { } private val deviceEntryIconTransition = kosmos.fakeDeviceEntryIconViewModelTransition private val testScope = kosmos.testScope - private val keyguardRepository = kosmos.fakeKeyguardRepository + private val biometricSettingsRepository = kosmos.fakeBiometricSettingsRepository private val accessibilityRepository = kosmos.fakeAccessibilityRepository private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository @@ -85,22 +86,12 @@ class UdfpsAccessibilityOverlayViewModelTest : SysuiTestCase() { setupVisibleStateOnLockscreen() // AOD - keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.LOCKSCREEN, - to = KeyguardState.AOD, - value = 0f, - transitionState = TransitionState.STARTED, - ) - ) - keyguardTransitionRepository.sendTransitionStep( - TransitionStep( - from = KeyguardState.LOCKSCREEN, - to = KeyguardState.AOD, - value = 1f, - transitionState = TransitionState.FINISHED, - ) + keyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + this, ) + runCurrent() assertThat(visible).isFalse() } fun fpNotRunning_overlayNotVisible() = @@ -129,6 +120,7 @@ class UdfpsAccessibilityOverlayViewModelTest : SysuiTestCase() { // Listening for UDFPS fingerprintPropertyRepository.supportsUdfps() + biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) deviceEntryFingerprintAuthRepository.setIsRunning(true) deviceEntryRepository.setUnlocked(false) diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java index 9d9b263c5df5..2d3ca6095835 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java @@ -19,7 +19,13 @@ package com.android.systemui.globalactions; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; +import static org.mockito.Mockito.when; + +import android.nearby.NearbyManager; +import android.net.platform.flags.Flags; import android.os.PowerManager; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; @@ -32,6 +38,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.MockitoAnnotations; @SmallTest @@ -41,10 +48,13 @@ public class ShutdownUiTest extends SysuiTestCase { ShutdownUi mShutdownUi; @Mock BlurUtils mBlurUtils; + @Mock + NearbyManager mNearbyManager; @Before public void setUp() throws Exception { - mShutdownUi = new ShutdownUi(getContext(), mBlurUtils); + MockitoAnnotations.initMocks(this); + mShutdownUi = new ShutdownUi(getContext(), mBlurUtils, mNearbyManager); } @Test @@ -82,4 +92,53 @@ public class ShutdownUiTest extends SysuiTestCase { String message = mShutdownUi.getReasonMessage("anything-else"); assertNull(message); } + + @EnableFlags(Flags.FLAG_POWERED_OFF_FINDING_PLATFORM) + @Test + public void getDialog_whenPowerOffFindingModeEnabled_returnsFinderDialog() { + when(mNearbyManager.getPoweredOffFindingMode()).thenReturn( + NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED); + + int actualLayout = mShutdownUi.getShutdownDialogContent(false); + + int expectedLayout = com.android.systemui.res.R.layout.shutdown_dialog_finder_active; + assertEquals(actualLayout, expectedLayout); + } + + @DisableFlags(Flags.FLAG_POWERED_OFF_FINDING_PLATFORM) + @Test + public void getDialog_whenPowerOffFindingModeEnabledFlagDisabled_returnsFinderDialog() { + when(mNearbyManager.getPoweredOffFindingMode()).thenReturn( + NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED); + + int actualLayout = mShutdownUi.getShutdownDialogContent(false); + + int expectedLayout = R.layout.shutdown_dialog; + assertEquals(actualLayout, expectedLayout); + } + + @EnableFlags(Flags.FLAG_POWERED_OFF_FINDING_PLATFORM) + @Test + public void getDialog_whenPowerOffFindingModeDisabled_returnsDefaultDialog() { + when(mNearbyManager.getPoweredOffFindingMode()).thenReturn( + NearbyManager.POWERED_OFF_FINDING_MODE_DISABLED); + + int actualLayout = mShutdownUi.getShutdownDialogContent(false); + + int expectedLayout = R.layout.shutdown_dialog; + assertEquals(actualLayout, expectedLayout); + } + + @EnableFlags(Flags.FLAG_POWERED_OFF_FINDING_PLATFORM) + @Test + public void getDialog_whenPowerOffFindingModeEnabledAndIsReboot_returnsDefaultDialog() { + when(mNearbyManager.getPoweredOffFindingMode()).thenReturn( + NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED); + + int actualLayout = mShutdownUi.getShutdownDialogContent(true); + + int expectedLayout = R.layout.shutdown_dialog; + assertEquals(actualLayout, expectedLayout); + } + } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt index abd42387cc2e..69cd173f4253 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt @@ -129,7 +129,6 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { val glanceableHubTransitions = GlanceableHubTransitions( - scope = testScope, bgDispatcher = kosmos.testDispatcher, transitionInteractor = transitionInteractor, transitionRepository = transitionRepository, @@ -1812,26 +1811,40 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() { @Test fun glanceableHubToDreaming() = testScope.runTest { - // GIVEN a device that is not dreaming or dozing - keyguardRepository.setDreamingWithOverlay(false) + // GIVEN that we are dreaming and not dozing + keyguardRepository.setDreaming(true) keyguardRepository.setDozeTransitionModel( DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH) ) runCurrent() // GIVEN a prior transition has run to GLANCEABLE_HUB - runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.GLANCEABLE_HUB) + runTransitionAndSetWakefulness(KeyguardState.DREAMING, KeyguardState.GLANCEABLE_HUB) + runCurrent() - // WHEN the device begins to dream - keyguardRepository.setDreamingWithOverlay(true) - advanceTimeBy(100L) + // WHEN a transition away from glanceable hub starts + val currentScene = CommunalSceneKey.Communal + val targetScene = CommunalSceneKey.Blank + + val transitionState = + MutableStateFlow<ObservableCommunalTransitionState>( + ObservableCommunalTransitionState.Transition( + fromScene = currentScene, + toScene = targetScene, + progress = flowOf(0f, 0.1f), + isInitiatedByUserInput = false, + isUserInputOngoing = flowOf(false), + ) + ) + communalInteractor.setTransitionState(transitionState) + runCurrent() assertThat(transitionRepository) .startedTransition( ownerName = FromGlanceableHubTransitionInteractor::class.simpleName, from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.DREAMING, - animatorAssertion = { it.isNotNull() }, + animatorAssertion = { it.isNull() }, // transition should be manually animated ) coroutineContext.cancelChildren() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt new file mode 100644 index 000000000000..02bd810a43d5 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository +import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository +import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository +import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.keyguard.data.repository.keyguardRepository +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlin.test.Test +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.runner.RunWith + +@ExperimentalCoroutinesApi +@SmallTest +@RunWith(AndroidJUnit4::class) +class DeviceEntryIconViewModelTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + private lateinit var keyguardRepository: FakeKeyguardRepository + private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository + private lateinit var fingerprintAuthRepository: FakeDeviceEntryFingerprintAuthRepository + private lateinit var deviceEntryIconTransition: FakeDeviceEntryIconTransition + private lateinit var underTest: DeviceEntryIconViewModel + + @Before + fun setUp() { + keyguardRepository = kosmos.fakeKeyguardRepository + fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository + fingerprintAuthRepository = kosmos.fakeDeviceEntryFingerprintAuthRepository + deviceEntryIconTransition = kosmos.fakeDeviceEntryIconViewModelTransition + underTest = kosmos.deviceEntryIconViewModel + } + + @Test + fun isLongPressEnabled_udfpsRunning() = + testScope.runTest { + val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled) + fingerprintPropertyRepository.supportsUdfps() + fingerprintAuthRepository.setIsRunning(true) + keyguardRepository.setKeyguardDismissible(false) + assertThat(isLongPressEnabled).isFalse() + } + + @Test + fun isLongPressEnabled_unlocked() = + testScope.runTest { + val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled) + keyguardRepository.setKeyguardDismissible(true) + assertThat(isLongPressEnabled).isTrue() + } + + @Test + fun isLongPressEnabled_lock() = + testScope.runTest { + val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled) + keyguardRepository.setKeyguardDismissible(false) + + // udfps supported + fingerprintPropertyRepository.supportsUdfps() + assertThat(isLongPressEnabled).isTrue() + + // udfps isn't supported + fingerprintPropertyRepository.supportsRearFps() + assertThat(isLongPressEnabled).isFalse() + } + + @Test + fun isVisible() = + testScope.runTest { + val isVisible by collectLastValue(underTest.isVisible) + deviceEntryIconTransitionAlpha(1f) + assertThat(isVisible).isTrue() + + deviceEntryIconTransitionAlpha(0f) + assertThat(isVisible).isFalse() + + deviceEntryIconTransitionAlpha(.5f) + assertThat(isVisible).isTrue() + } + + private fun deviceEntryIconTransitionAlpha(alpha: Float) { + deviceEntryIconTransition.setDeviceEntryParentViewAlpha(alpha) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/media/OWNERS new file mode 100644 index 000000000000..e6f218f85b1f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/OWNERS @@ -0,0 +1 @@ +include /packages/SystemUI/src/com/android/systemui/media/OWNERS diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt index 2e7829d4ea7b..2f92afa39b52 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt @@ -1247,7 +1247,7 @@ public class MediaControlPanelTest : SysuiTestCase() { } @Test - @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(com.android.settingslib.flags.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) fun bindBroadcastButton() { initMediaViewHolderMocks() initDeviceMediaData(true, APP_NAME) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java index e2cf87a6dd62..087988469a49 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java @@ -28,6 +28,7 @@ import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; +import com.android.settingslib.flags.Flags; import com.android.settingslib.media.MediaOutputConstants; import com.android.systemui.SysuiTestCase; @@ -84,7 +85,20 @@ public class MediaOutputDialogReceiverTest extends SysuiTestCase { } @Test + public void launchMediaOutputBroadcastDialog_flagOff_broadcastDialogFactoryNotCalled() { + mSetFlagsRule.disableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING); + Intent intent = new Intent( + MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG); + intent.putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, getContext().getPackageName()); + mMediaOutputDialogReceiver.onReceive(getContext(), intent); + + verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any()); + verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any()); + } + + @Test public void launchMediaOutputBroadcastDialog_ExtraPackageName_BroadcastDialogFactoryCalled() { + mSetFlagsRule.enableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING); Intent intent = new Intent( MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG); intent.putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, getContext().getPackageName()); @@ -97,6 +111,7 @@ public class MediaOutputDialogReceiverTest extends SysuiTestCase { @Test public void launchMediaOutputBroadcastDialog_WrongExtraKey_DialogBroadcastFactoryNotCalled() { + mSetFlagsRule.enableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING); Intent intent = new Intent( MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG); intent.putExtra("Wrong Package Name Key", getContext().getPackageName()); @@ -108,6 +123,7 @@ public class MediaOutputDialogReceiverTest extends SysuiTestCase { @Test public void launchMediaOutputBroadcastDialog_NoExtra_BroadcastDialogFactoryNotCalled() { + mSetFlagsRule.enableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING); Intent intent = new Intent( MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG); mMediaOutputDialogReceiver.onReceive(getContext(), intent); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java index d9ddc8e6b23b..84300da82a30 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java @@ -50,6 +50,7 @@ import com.android.internal.logging.UiEventLogger; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; +import com.android.settingslib.flags.Flags; import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.MediaDevice; import com.android.systemui.SysuiTestCase; @@ -177,7 +178,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void getStopButtonVisibility_remoteBLEDevice_returnVisible() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); @@ -189,7 +190,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void getStopButtonVisibility_remoteNonBLEDevice_returnGone() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); @@ -210,7 +211,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void isBroadcastSupported_flagOnAndConnectBleDevice_returnsTrue() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); @@ -223,7 +224,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void isBroadcastSupported_flagOnAndNoBleDevice_returnsFalse() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); @@ -236,7 +237,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void isBroadcastSupported_notSupportBroadcastAndflagOn_returnsFalse() { FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true); @@ -245,7 +246,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void isBroadcastSupported_flagOffAndConnectToBleDevice_returnsTrue() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); @@ -258,7 +259,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void isBroadcastSupported_flagOffAndNoBleDevice_returnsTrue() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); @@ -271,7 +272,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void isBroadcastSupported_noBleDeviceAndEnabledBroadcast_returnsTrue() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); @@ -284,7 +285,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void isBroadcastSupported_noBleDeviceAndDisabledBroadcast_returnsFalse() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); @@ -297,7 +298,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void getBroadcastIconVisibility_isBroadcasting_returnVisible() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); @@ -309,7 +310,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void getBroadcastIconVisibility_noBroadcasting_returnGone() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); @@ -321,7 +322,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void getBroadcastIconVisibility_remoteNonLeDevice_returnGone() { when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn( mLocalBluetoothLeBroadcast); @@ -374,7 +375,7 @@ public class MediaOutputDialogTest extends SysuiTestCase { } @Test - @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING) + @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) public void getStopButtonText_supportsBroadcast_returnsBroadcastText() { String stopText = mContext.getText(R.string.media_output_broadcast).toString(); MediaDevice mMediaDevice = mock(MediaDevice.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/OWNERS new file mode 100644 index 000000000000..100dd2e9cbb8 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/OWNERS @@ -0,0 +1 @@ +include /packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/OWNERS new file mode 100644 index 000000000000..f87d93a24939 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/OWNERS @@ -0,0 +1 @@ +include /packages/SystemUI/src/com/android/systemui/mediaprojection/OWNERS diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt deleted file mode 100644 index e044eeca8303..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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.mediaprojection.permission - -import android.app.AlertDialog -import android.media.projection.MediaProjectionConfig -import android.testing.AndroidTestingRunner -import android.testing.TestableLooper -import android.view.WindowManager -import android.widget.Spinner -import android.widget.TextView -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.flags.FeatureFlagsClassic -import com.android.systemui.flags.Flags -import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger -import com.android.systemui.res.R -import com.android.systemui.statusbar.phone.AlertDialogWithDelegate -import com.android.systemui.statusbar.phone.SystemUIDialog -import com.android.systemui.util.mockito.mock -import junit.framework.Assert.assertEquals -import org.junit.After -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mockito.`when` as whenever - -@SmallTest -@RunWith(AndroidTestingRunner::class) -@TestableLooper.RunWithLooper(setAsMainLooper = true) -class MediaProjectionPermissionDialogDelegateTest : SysuiTestCase() { - - private lateinit var dialog: AlertDialog - - private val flags = mock<FeatureFlagsClassic>() - private val onStartRecordingClicked = mock<Runnable>() - private val mediaProjectionMetricsLogger = mock<MediaProjectionMetricsLogger>() - - private val mediaProjectionConfig: MediaProjectionConfig = - MediaProjectionConfig.createConfigForDefaultDisplay() - private val appName: String = "testApp" - private val hostUid: Int = 12345 - - private val resIdSingleApp = R.string.screen_share_permission_dialog_option_single_app - private val resIdFullScreen = R.string.screen_share_permission_dialog_option_entire_screen - private val resIdSingleAppDisabled = - R.string.media_projection_entry_app_permission_dialog_single_app_disabled - - @Before - fun setUp() { - whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true) - } - - @After - fun teardown() { - if (::dialog.isInitialized) { - dialog.dismiss() - } - } - - @Test - fun showDialog_forceShowPartialScreenShareFalse() { - // Set up dialog with MediaProjectionConfig.createConfigForDefaultDisplay() and - // overrideDisableSingleAppOption = false - val overrideDisableSingleAppOption = false - setUpAndShowDialog(overrideDisableSingleAppOption) - - val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_spinner) - val secondOptionText = - spinner.adapter - .getDropDownView(1, null, spinner) - .findViewById<TextView>(android.R.id.text2) - ?.text - - // check that the first option is full screen and enabled - assertEquals(context.getString(resIdFullScreen), spinner.selectedItem) - - // check that the second option is single app and disabled - assertEquals(context.getString(resIdSingleAppDisabled, appName), secondOptionText) - } - - @Test - fun showDialog_forceShowPartialScreenShareTrue() { - // Set up dialog with MediaProjectionConfig.createConfigForDefaultDisplay() and - // overrideDisableSingleAppOption = true - val overrideDisableSingleAppOption = true - setUpAndShowDialog(overrideDisableSingleAppOption) - - val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_spinner) - val secondOptionText = - spinner.adapter - .getDropDownView(1, null, spinner) - .findViewById<TextView>(android.R.id.text1) - ?.text - - // check that the first option is single app and enabled - assertEquals(context.getString(resIdSingleApp), spinner.selectedItem) - - // check that the second option is full screen and enabled - assertEquals(context.getString(resIdFullScreen), secondOptionText) - } - - private fun setUpAndShowDialog(overrideDisableSingleAppOption: Boolean) { - val delegate = - MediaProjectionPermissionDialogDelegate( - context, - mediaProjectionConfig, - {}, - onStartRecordingClicked, - appName, - overrideDisableSingleAppOption, - hostUid, - mediaProjectionMetricsLogger - ) - - dialog = AlertDialogWithDelegate(context, R.style.Theme_SystemUI_Dialog, delegate) - SystemUIDialog.applyFlags(dialog) - SystemUIDialog.setDialogSize(dialog) - - dialog.window?.addSystemFlags( - WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS - ) - - delegate.onCreate(dialog, savedInstanceState = null) - dialog.show() - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt index 70b04175da91..8ecb95334bc4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogDelegateTest.kt @@ -16,6 +16,7 @@ package com.android.systemui.qs.tiles.dialog.bluetooth +import android.content.Context import android.graphics.drawable.Drawable import android.testing.AndroidTestingRunner import android.testing.TestableLooper @@ -31,7 +32,13 @@ import androidx.test.filters.SmallTest import com.android.internal.logging.UiEventLogger import com.android.settingslib.bluetooth.CachedBluetoothDevice import com.android.systemui.SysuiTestCase +import com.android.systemui.animation.DialogTransitionAnimator +import com.android.systemui.model.SysUiState import com.android.systemui.res.R +import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.statusbar.phone.SystemUIDialogManager +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.CoroutineDispatcher @@ -43,6 +50,8 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyBoolean +import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit @@ -51,7 +60,7 @@ import org.mockito.junit.MockitoRule @SmallTest @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) -class BluetoothTileDialogTest : SysuiTestCase() { +class BluetoothTileDialogDelegateTest : SysuiTestCase() { companion object { const val DEVICE_NAME = "device" const val DEVICE_CONNECTION_SUMMARY = "active" @@ -76,6 +85,10 @@ class BluetoothTileDialogTest : SysuiTestCase() { isBluetoothEnabled = ENABLED, isAutoOnToggleFeatureAvailable = ENABLED ) + @Mock private lateinit var sysuiDialogFactory: SystemUIDialog.Factory + @Mock private lateinit var dialogManager: SystemUIDialogManager + @Mock private lateinit var sysuiState: SysUiState + @Mock private lateinit var dialogTransitionAnimator: DialogTransitionAnimator private val fakeSystemClock = FakeSystemClock() @@ -83,7 +96,7 @@ class BluetoothTileDialogTest : SysuiTestCase() { private lateinit var dispatcher: CoroutineDispatcher private lateinit var testScope: TestScope private lateinit var icon: Pair<Drawable, String> - private lateinit var bluetoothTileDialog: BluetoothTileDialog + private lateinit var mBluetoothTileDialogDelegate: BluetoothTileDialogDelegate private lateinit var deviceItem: DeviceItem @Before @@ -91,18 +104,44 @@ class BluetoothTileDialogTest : SysuiTestCase() { scheduler = TestCoroutineScheduler() dispatcher = UnconfinedTestDispatcher(scheduler) testScope = TestScope(dispatcher) - bluetoothTileDialog = - BluetoothTileDialog( - ENABLED, + + whenever(sysuiState.setFlag(anyInt(), anyBoolean())).thenReturn(sysuiState) + + mBluetoothTileDialogDelegate = + BluetoothTileDialogDelegate( + mContext, uiProperties, CONTENT_HEIGHT, + ENABLED, bluetoothTileDialogCallback, + {}, dispatcher, fakeSystemClock, uiEventLogger, logger, - mContext + sysuiDialogFactory, + LayoutInflater.from(mContext) ) + + whenever( + sysuiDialogFactory.create( + any(SystemUIDialog.Delegate::class.java), + any(Context::class.java) + ) + ) + .thenAnswer { + SystemUIDialog( + mContext, + 0, + SystemUIDialog.DEFAULT_DISMISS_ON_DEVICE_LOCK, + dialogManager, + sysuiState, + fakeBroadcastDispatcher, + dialogTransitionAnimator, + it.getArgument(0) + ) + } + icon = Pair(drawable, DEVICE_NAME) deviceItem = DeviceItem( @@ -118,11 +157,11 @@ class BluetoothTileDialogTest : SysuiTestCase() { @Test fun testShowDialog_createRecyclerViewWithAdapter() { - bluetoothTileDialog.show() + val dialog = mBluetoothTileDialogDelegate.createDialog() + dialog.show() - val recyclerView = bluetoothTileDialog.requireViewById<RecyclerView>(R.id.device_list) + val recyclerView = dialog.requireViewById<RecyclerView>(R.id.device_list) - assertThat(bluetoothTileDialog.isShowing).isTrue() assertThat(recyclerView).isNotNull() assertThat(recyclerView.visibility).isEqualTo(VISIBLE) assertThat(recyclerView.adapter).isNotNull() @@ -132,28 +171,18 @@ class BluetoothTileDialogTest : SysuiTestCase() { @Test fun testShowDialog_displayBluetoothDevice() { testScope.runTest { - bluetoothTileDialog = - BluetoothTileDialog( - ENABLED, - uiProperties, - CONTENT_HEIGHT, - bluetoothTileDialogCallback, - dispatcher, - fakeSystemClock, - uiEventLogger, - logger, - mContext - ) - bluetoothTileDialog.show() + val dialog = mBluetoothTileDialogDelegate.createDialog() + dialog.show() fakeSystemClock.setElapsedRealtime(Long.MAX_VALUE) - bluetoothTileDialog.onDeviceItemUpdated( + mBluetoothTileDialogDelegate.onDeviceItemUpdated( + dialog, listOf(deviceItem), showSeeAll = false, showPairNewDevice = false ) - val recyclerView = bluetoothTileDialog.requireViewById<RecyclerView>(R.id.device_list) - val adapter = recyclerView.adapter as BluetoothTileDialog.Adapter + val recyclerView = dialog.requireViewById<RecyclerView>(R.id.device_list) + val adapter = recyclerView?.adapter as BluetoothTileDialogDelegate.Adapter assertThat(adapter.itemCount).isEqualTo(1) assertThat(adapter.getItem(0).deviceName).isEqualTo(DEVICE_NAME) assertThat(adapter.getItem(0).connectionSummary).isEqualTo(DEVICE_CONNECTION_SUMMARY) @@ -168,17 +197,7 @@ class BluetoothTileDialogTest : SysuiTestCase() { val view = LayoutInflater.from(mContext).inflate(R.layout.bluetooth_device_item, null, false) val viewHolder = - BluetoothTileDialog( - ENABLED, - uiProperties, - CONTENT_HEIGHT, - bluetoothTileDialogCallback, - dispatcher, - fakeSystemClock, - uiEventLogger, - logger, - mContext - ) + mBluetoothTileDialogDelegate .Adapter(bluetoothTileDialogCallback) .DeviceItemViewHolder(view) viewHolder.bind(deviceItem, bluetoothTileDialogCallback) @@ -196,16 +215,19 @@ class BluetoothTileDialogTest : SysuiTestCase() { val view = LayoutInflater.from(mContext).inflate(R.layout.bluetooth_device_item, null, false) val viewHolder = - BluetoothTileDialog( - ENABLED, + BluetoothTileDialogDelegate( + mContext, uiProperties, CONTENT_HEIGHT, + ENABLED, bluetoothTileDialogCallback, + {}, dispatcher, fakeSystemClock, uiEventLogger, logger, - mContext + sysuiDialogFactory, + LayoutInflater.from(mContext) ) .Adapter(bluetoothTileDialogCallback) .DeviceItemViewHolder(view) @@ -220,32 +242,21 @@ class BluetoothTileDialogTest : SysuiTestCase() { @Test fun testOnDeviceUpdated_hideSeeAll_showPairNew() { testScope.runTest { - bluetoothTileDialog = - BluetoothTileDialog( - ENABLED, - uiProperties, - CONTENT_HEIGHT, - bluetoothTileDialogCallback, - dispatcher, - fakeSystemClock, - uiEventLogger, - logger, - mContext - ) - bluetoothTileDialog.show() + val dialog = mBluetoothTileDialogDelegate.createDialog() + dialog.show() fakeSystemClock.setElapsedRealtime(Long.MAX_VALUE) - bluetoothTileDialog.onDeviceItemUpdated( + mBluetoothTileDialogDelegate.onDeviceItemUpdated( + dialog, listOf(deviceItem), showSeeAll = false, showPairNewDevice = true ) - val seeAllButton = bluetoothTileDialog.requireViewById<View>(R.id.see_all_button) - val pairNewButton = - bluetoothTileDialog.requireViewById<View>(R.id.pair_new_device_button) - val recyclerView = bluetoothTileDialog.requireViewById<RecyclerView>(R.id.device_list) - val adapter = recyclerView.adapter as BluetoothTileDialog.Adapter - val scrollViewContent = bluetoothTileDialog.requireViewById<View>(R.id.scroll_view) + val seeAllButton = dialog.requireViewById<View>(R.id.see_all_button) + val pairNewButton = dialog.requireViewById<View>(R.id.pair_new_device_button) + val recyclerView = dialog.requireViewById<RecyclerView>(R.id.device_list) + val adapter = recyclerView?.adapter as BluetoothTileDialogDelegate.Adapter + val scrollViewContent = dialog.requireViewById<View>(R.id.scroll_view) assertThat(seeAllButton).isNotNull() assertThat(seeAllButton.visibility).isEqualTo(GONE) @@ -260,22 +271,24 @@ class BluetoothTileDialogTest : SysuiTestCase() { fun testShowDialog_cachedHeightLargerThanMinHeight_displayFromCachedHeight() { testScope.runTest { val cachedHeight = Int.MAX_VALUE - bluetoothTileDialog = - BluetoothTileDialog( - ENABLED, - uiProperties, - cachedHeight, - bluetoothTileDialogCallback, - dispatcher, - fakeSystemClock, - uiEventLogger, - logger, - mContext - ) - bluetoothTileDialog.show() - assertThat( - bluetoothTileDialog.requireViewById<View>(R.id.scroll_view).layoutParams.height - ) + val dialog = + BluetoothTileDialogDelegate( + mContext, + BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED), + cachedHeight, + ENABLED, + bluetoothTileDialogCallback, + {}, + dispatcher, + fakeSystemClock, + uiEventLogger, + logger, + sysuiDialogFactory, + LayoutInflater.from(mContext) + ) + .createDialog() + dialog.show() + assertThat(dialog.requireViewById<View>(R.id.scroll_view).layoutParams.height) .isEqualTo(cachedHeight) } } @@ -283,22 +296,24 @@ class BluetoothTileDialogTest : SysuiTestCase() { @Test fun testShowDialog_cachedHeightLessThanMinHeight_displayFromUiProperties() { testScope.runTest { - bluetoothTileDialog = - BluetoothTileDialog( - ENABLED, - uiProperties, - MATCH_PARENT, - bluetoothTileDialogCallback, - dispatcher, - fakeSystemClock, - uiEventLogger, - logger, - mContext - ) - bluetoothTileDialog.show() - assertThat( - bluetoothTileDialog.requireViewById<View>(R.id.scroll_view).layoutParams.height - ) + val dialog = + BluetoothTileDialogDelegate( + mContext, + BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED), + MATCH_PARENT, + ENABLED, + bluetoothTileDialogCallback, + {}, + dispatcher, + fakeSystemClock, + uiEventLogger, + logger, + sysuiDialogFactory, + LayoutInflater.from(mContext) + ) + .createDialog() + dialog.show() + assertThat(dialog.requireViewById<View>(R.id.scroll_view).layoutParams.height) .isGreaterThan(MATCH_PARENT) } } @@ -306,23 +321,25 @@ class BluetoothTileDialogTest : SysuiTestCase() { @Test fun testShowDialog_bluetoothEnabled_autoOnToggleGone() { testScope.runTest { - bluetoothTileDialog = - BluetoothTileDialog( - ENABLED, - BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED), - MATCH_PARENT, - bluetoothTileDialogCallback, - dispatcher, - fakeSystemClock, - uiEventLogger, - logger, - mContext - ) - bluetoothTileDialog.show() + val dialog = + BluetoothTileDialogDelegate( + mContext, + BluetoothTileDialogViewModel.UiProperties.build(ENABLED, ENABLED), + MATCH_PARENT, + ENABLED, + bluetoothTileDialogCallback, + {}, + dispatcher, + fakeSystemClock, + uiEventLogger, + logger, + sysuiDialogFactory, + LayoutInflater.from(mContext) + ) + .createDialog() + dialog.show() assertThat( - bluetoothTileDialog - .requireViewById<View>(R.id.bluetooth_auto_on_toggle_layout) - .visibility + dialog.requireViewById<View>(R.id.bluetooth_auto_on_toggle_layout).visibility ) .isEqualTo(GONE) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt index cb9f4b4e4810..39e2413be40e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt @@ -16,7 +16,6 @@ package com.android.systemui.qs.tiles.dialog.bluetooth -import android.content.SharedPreferences import android.content.pm.UserInfo import android.testing.AndroidTestingRunner import android.testing.TestableLooper @@ -31,10 +30,14 @@ import com.android.settingslib.flags.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.user.data.repository.FakeUserRepository +import com.android.systemui.util.FakeSharedPreferences import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.kotlin.getMutableStateFlow import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.nullable +import com.android.systemui.util.mockito.whenever import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat @@ -50,12 +53,12 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.anyBoolean import org.mockito.Mockito.never import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule @@ -84,9 +87,15 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() { @Mock private lateinit var uiEventLogger: UiEventLogger - @Mock private lateinit var logger: BluetoothTileDialogLogger + @Mock + private lateinit var mBluetoothTileDialogDelegateDelegateFactory: + BluetoothTileDialogDelegate.Factory - @Mock private lateinit var sharedPreferences: SharedPreferences + @Mock private lateinit var bluetoothTileDialogDelegate: BluetoothTileDialogDelegate + + @Mock private lateinit var sysuiDialog: SystemUIDialog + + private val sharedPreferences = FakeSharedPreferences() private lateinit var scheduler: TestCoroutineScheduler private lateinit var dispatcher: CoroutineDispatcher @@ -123,20 +132,38 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() { ), mDialogTransitionAnimator, activityStarter, - fakeSystemClock, uiEventLogger, - logger, testScope.backgroundScope, dispatcher, dispatcher, sharedPreferences, + mBluetoothTileDialogDelegateDelegateFactory ) - `when`(deviceItemInteractor.deviceItemUpdate).thenReturn(MutableSharedFlow()) - `when`(bluetoothStateInteractor.bluetoothStateUpdate) + whenever(deviceItemInteractor.deviceItemUpdate).thenReturn(MutableSharedFlow()) + whenever(bluetoothStateInteractor.bluetoothStateUpdate) .thenReturn(MutableStateFlow(null).asStateFlow()) - `when`(deviceItemInteractor.deviceItemUpdateRequest) + whenever(deviceItemInteractor.deviceItemUpdateRequest) .thenReturn(MutableStateFlow(Unit).asStateFlow()) - `when`(bluetoothStateInteractor.isBluetoothEnabled).thenReturn(true) + whenever(bluetoothStateInteractor.isBluetoothEnabled).thenReturn(true) + whenever( + mBluetoothTileDialogDelegateDelegateFactory.create( + any(), + any(), + anyInt(), + ArgumentMatchers.anyBoolean(), + any(), + any() + ) + ) + .thenReturn(bluetoothTileDialogDelegate) + whenever(bluetoothTileDialogDelegate.createDialog()).thenReturn(sysuiDialog) + whenever(bluetoothTileDialogDelegate.bluetoothStateToggle) + .thenReturn(getMutableStateFlow(false)) + whenever(bluetoothTileDialogDelegate.deviceItemClick) + .thenReturn(getMutableStateFlow(deviceItem)) + whenever(bluetoothTileDialogDelegate.contentHeight).thenReturn(getMutableStateFlow(0)) + whenever(bluetoothTileDialogDelegate.bluetoothAutoOnToggle) + .thenReturn(getMutableStateFlow(false)) } @Test @@ -145,7 +172,6 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() { bluetoothTileDialogViewModel.showDialog(context, null) verify(mDialogTransitionAnimator, never()).showFromView(any(), any(), any(), any()) - verify(uiEventLogger).log(BluetoothTileDialogUiEvent.BLUETOOTH_TILE_DIALOG_SHOWN) } } @@ -191,7 +217,7 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() { @Test fun testStartSettingsActivity_activityLaunched_dialogDismissed() { testScope.runTest { - `when`(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice) + whenever(deviceItem.cachedBluetoothDevice).thenReturn(cachedBluetoothDevice) bluetoothTileDialogViewModel.showDialog(context, null) val clickedView = View(context) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactoryTest.kt index 92c73261a95e..a8cd8c801a95 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactoryTest.kt @@ -16,10 +16,18 @@ package com.android.systemui.qs.tiles.dialog.bluetooth +import android.bluetooth.BluetoothDevice +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.media.AudioManager +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest +import com.android.settingslib.bluetooth.BluetoothUtils import com.android.settingslib.bluetooth.CachedBluetoothDevice +import com.android.settingslib.flags.Flags import com.android.systemui.SysuiTestCase import com.google.common.truth.Truth.assertThat import org.junit.Before @@ -35,19 +43,26 @@ import org.mockito.junit.MockitoRule @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) class DeviceItemFactoryTest : SysuiTestCase() { - @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule() @Mock private lateinit var cachedDevice: CachedBluetoothDevice + @Mock private lateinit var bluetoothDevice: BluetoothDevice + @Mock private lateinit var packageManager: PackageManager private val availableMediaDeviceItemFactory = AvailableMediaDeviceItemFactory() private val connectedDeviceItemFactory = ConnectedDeviceItemFactory() private val savedDeviceItemFactory = SavedDeviceItemFactory() + private val audioManager = context.getSystemService(AudioManager::class.java)!! + @Before fun setup() { `when`(cachedDevice.name).thenReturn(DEVICE_NAME) + `when`(cachedDevice.address).thenReturn(DEVICE_ADDRESS) + `when`(cachedDevice.device).thenReturn(bluetoothDevice) `when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY) + + context.setMockPackageManager(packageManager) } @Test @@ -72,6 +87,225 @@ class DeviceItemFactoryTest : SysuiTestCase() { assertThat(deviceItem.background).isNotNull() } + @Test + @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testSavedFactory_isFilterMatched_bondedAndNotConnected_returnsTrue() { + `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(cachedDevice.isConnected).thenReturn(false) + + assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isTrue() + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testSavedFactory_isFilterMatched_connected_returnsFalse() { + `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(cachedDevice.isConnected).thenReturn(true) + + assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isFalse() + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testSavedFactory_isFilterMatched_notBonded_returnsFalse() { + `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE) + `when`(cachedDevice.isConnected).thenReturn(false) + + assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isFalse() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testSavedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() { + val exclusiveManagerName = + BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME + `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)) + .thenReturn(exclusiveManagerName.toByteArray()) + `when`(packageManager.getPackageInfo(exclusiveManagerName, 0)).thenReturn(PackageInfo()) + `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(cachedDevice.isConnected).thenReturn(false) + + assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isFalse() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testSavedFactory_isFilterMatched_noExclusiveManager_returnsTrue() { + `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(cachedDevice.isConnected).thenReturn(false) + + assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isTrue() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testSavedFactory_isFilterMatched_notAllowedExclusiveManager_returnsTrue() { + `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)) + .thenReturn(FAKE_EXCLUSIVE_MANAGER_NAME.toByteArray()) + `when`(packageManager.getPackageInfo(FAKE_EXCLUSIVE_MANAGER_NAME, 0)) + .thenReturn(PackageInfo()) + `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(cachedDevice.isConnected).thenReturn(false) + + assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isTrue() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testSavedFactory_isFilterMatched_uninstalledExclusiveManager_returnsTrue() { + val exclusiveManagerName = + BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME + `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)) + .thenReturn(exclusiveManagerName.toByteArray()) + `when`(packageManager.getPackageInfo(exclusiveManagerName, 0)) + .thenThrow(PackageManager.NameNotFoundException("Test!")) + `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(cachedDevice.isConnected).thenReturn(false) + + assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isTrue() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testSavedFactory_isFilterMatched_notExclusivelyManaged_notBonded_returnsFalse() { + `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE) + `when`(cachedDevice.isConnected).thenReturn(false) + + assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isFalse() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testSavedFactory_isFilterMatched_notExclusivelyManaged_connected_returnsFalse() { + `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(cachedDevice.isConnected).thenReturn(true) + + assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isFalse() + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testConnectedFactory_isFilterMatched_bondedAndConnected_returnsTrue() { + `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(bluetoothDevice.isConnected).thenReturn(true) + audioManager.setMode(AudioManager.MODE_NORMAL) + + assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isTrue() + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testConnectedFactory_isFilterMatched_notConnected_returnsFalse() { + `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(bluetoothDevice.isConnected).thenReturn(false) + audioManager.setMode(AudioManager.MODE_NORMAL) + + assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isFalse() + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testConnectedFactory_isFilterMatched_notBonded_returnsFalse() { + `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE) + `when`(bluetoothDevice.isConnected).thenReturn(true) + audioManager.setMode(AudioManager.MODE_NORMAL) + + assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isFalse() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testConnectedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() { + val exclusiveManagerName = + BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME + `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)) + .thenReturn(exclusiveManagerName.toByteArray()) + `when`(packageManager.getPackageInfo(exclusiveManagerName, 0)).thenReturn(PackageInfo()) + `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(bluetoothDevice.isConnected).thenReturn(true) + audioManager.setMode(AudioManager.MODE_NORMAL) + + assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isFalse() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testConnectedFactory_isFilterMatched_noExclusiveManager_returnsTrue() { + `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(bluetoothDevice.isConnected).thenReturn(true) + audioManager.setMode(AudioManager.MODE_NORMAL) + + assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isTrue() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testConnectedFactory_isFilterMatched_notAllowedExclusiveManager_returnsTrue() { + `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)) + .thenReturn(FAKE_EXCLUSIVE_MANAGER_NAME.toByteArray()) + `when`(packageManager.getPackageInfo(FAKE_EXCLUSIVE_MANAGER_NAME, 0)) + .thenReturn(PackageInfo()) + `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(bluetoothDevice.isConnected).thenReturn(true) + audioManager.setMode(AudioManager.MODE_NORMAL) + + assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isTrue() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testConnectedFactory_isFilterMatched_uninstalledExclusiveManager_returnsTrue() { + val exclusiveManagerName = + BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME + `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)) + .thenReturn(exclusiveManagerName.toByteArray()) + `when`(packageManager.getPackageInfo(exclusiveManagerName, 0)) + .thenThrow(PackageManager.NameNotFoundException("Test!")) + `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(bluetoothDevice.isConnected).thenReturn(true) + audioManager.setMode(AudioManager.MODE_NORMAL) + + assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isTrue() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testConnectedFactory_isFilterMatched_notExclusivelyManaged_notBonded_returnsFalse() { + `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE) + `when`(bluetoothDevice.isConnected).thenReturn(true) + audioManager.setMode(AudioManager.MODE_NORMAL) + + assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isFalse() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE) + fun testConnectedFactory_isFilterMatched_notExclusivelyManaged_notConnected_returnsFalse() { + `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED) + `when`(bluetoothDevice.isConnected).thenReturn(false) + audioManager.setMode(AudioManager.MODE_NORMAL) + + assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager)) + .isFalse() + } + private fun assertDeviceItem(deviceItem: DeviceItem?, deviceItemType: DeviceItemType) { assertThat(deviceItem).isNotNull() assertThat(deviceItem!!.type).isEqualTo(deviceItemType) @@ -83,5 +317,7 @@ class DeviceItemFactoryTest : SysuiTestCase() { companion object { const val DEVICE_NAME = "DeviceName" const val CONNECTION_SUMMARY = "ConnectionSummary" + private const val FAKE_EXCLUSIVE_MANAGER_NAME = "com.fake.name" + private const val DEVICE_ADDRESS = "04:52:C7:0B:D8:3C" } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt index e236f4a7730f..ddf0b9a78165 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt @@ -279,6 +279,7 @@ class DeviceItemInteractorTest : SysuiTestCase() { ): DeviceItemFactory { return object : DeviceItemFactory() { override fun isFilterMatched( + context: Context, cachedDevice: CachedBluetoothDevice, audioManager: AudioManager? ) = isFilterMatchFunc(cachedDevice) diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt index fbb77cdc3049..25dd9fedba7c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/SaveImageInBackgroundTaskTest.kt @@ -34,7 +34,6 @@ import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import java.util.concurrent.CompletableFuture -import java.util.function.Supplier import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Before @@ -46,8 +45,6 @@ class SaveImageInBackgroundTaskTest : SysuiTestCase() { private val smartActions = mock<ScreenshotSmartActions>() private val smartActionsProvider = mock<ScreenshotNotificationSmartActionsProvider>() private val saveImageData = SaveImageInBackgroundData() - private val sharedTransitionSupplier = - mock<Supplier<ScreenshotController.SavedImageData.ActionTransition>>() private val testScreenshotId: String = "testScreenshotId" private val testBitmap = mock<Bitmap>() private val testUser = UserHandle.getUserHandleForUid(0) @@ -88,7 +85,6 @@ class SaveImageInBackgroundTaskTest : SysuiTestCase() { imageExporter, smartActions, saveImageData, - sharedTransitionSupplier, smartActionsProvider, ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java index 85c8ba7e77b3..2a9aca7f5a35 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java @@ -20,8 +20,6 @@ import static com.android.systemui.screenshot.ScreenshotNotificationSmartActions import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.doThrow; @@ -32,19 +30,15 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Notification; -import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; -import android.os.Bundle; import android.os.Handler; -import android.os.Looper; import android.os.UserHandle; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition; import org.junit.Before; import org.junit.Test; @@ -84,7 +78,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { ScreenshotNotificationSmartActionsProvider smartActionsProvider = mock( ScreenshotNotificationSmartActionsProvider.class); when(smartActionsProvider.getActions(any(), any(), any(), any(), any(), any())) - .thenThrow(RuntimeException.class); + .thenThrow(RuntimeException.class); CompletableFuture<List<Notification.Action>> smartActionsFuture = mScreenshotSmartActions.getSmartActionsFuture( "", Uri.parse("content://authority/data"), bitmap, smartActionsProvider, @@ -166,89 +160,4 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { List<Notification.Action> smartActions = smartActionsFuture.get(5, TimeUnit.MILLISECONDS); assertEquals(smartActions.size(), 0); } - - // Tests for share action extras - @Test - public void testShareActionExtras() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - - ScreenshotController.SaveImageInBackgroundData - data = new ScreenshotController.SaveImageInBackgroundData(); - data.image = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); - data.finisher = null; - data.mActionsReadyListener = null; - SaveImageInBackgroundTask task = - new SaveImageInBackgroundTask(mContext, null, null, mScreenshotSmartActions, data, - ActionTransition::new, mSmartActionsProvider); - - Notification.Action shareAction = task.createShareAction(mContext, mContext.getResources(), - Uri.parse("Screenshot_123.png"), true).get().action; - - Intent intent = shareAction.actionIntent.getIntent(); - assertNotNull(intent); - Bundle bundle = intent.getExtras(); - assertTrue(bundle.containsKey(ScreenshotController.EXTRA_ID)); - assertTrue(bundle.containsKey(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED)); - assertEquals(ScreenshotController.ACTION_TYPE_SHARE, shareAction.title); - assertEquals(Intent.ACTION_SEND, intent.getAction()); - } - - // Tests for edit action extras - @Test - public void testEditActionExtras() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - - ScreenshotController.SaveImageInBackgroundData - data = new ScreenshotController.SaveImageInBackgroundData(); - data.image = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); - data.finisher = null; - data.mActionsReadyListener = null; - SaveImageInBackgroundTask task = - new SaveImageInBackgroundTask(mContext, null, null, mScreenshotSmartActions, data, - ActionTransition::new, mSmartActionsProvider); - - Notification.Action editAction = task.createEditAction(mContext, mContext.getResources(), - Uri.parse("Screenshot_123.png"), true).get().action; - - Intent intent = editAction.actionIntent.getIntent(); - assertNotNull(intent); - Bundle bundle = intent.getExtras(); - assertTrue(bundle.containsKey(ScreenshotController.EXTRA_ID)); - assertTrue(bundle.containsKey(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED)); - assertEquals(ScreenshotController.ACTION_TYPE_EDIT, editAction.title); - assertEquals(Intent.ACTION_EDIT, intent.getAction()); - } - - // Tests for share action extras - @Test - public void testDeleteActionExtras() { - if (Looper.myLooper() == null) { - Looper.prepare(); - } - - ScreenshotController.SaveImageInBackgroundData - data = new ScreenshotController.SaveImageInBackgroundData(); - data.image = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); - data.finisher = null; - data.mActionsReadyListener = null; - SaveImageInBackgroundTask task = - new SaveImageInBackgroundTask(mContext, null, null, mScreenshotSmartActions, data, - ActionTransition::new, mSmartActionsProvider); - - Notification.Action deleteAction = task.createDeleteAction(mContext, - mContext.getResources(), - Uri.parse("Screenshot_123.png"), true); - - Intent intent = deleteAction.actionIntent.getIntent(); - assertNotNull(intent); - Bundle bundle = intent.getExtras(); - assertTrue(bundle.containsKey(ScreenshotController.EXTRA_ID)); - assertTrue(bundle.containsKey(ScreenshotController.EXTRA_SMART_ACTIONS_ENABLED)); - assertEquals(deleteAction.title, ScreenshotController.ACTION_TYPE_DELETE); - assertNull(intent.getAction()); - } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt index b94e483088f2..31acd86f52f4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt @@ -23,6 +23,7 @@ import android.testing.TestableLooper import android.view.View import android.view.ViewGroup import android.view.WindowManagerPolicyConstants.EXTRA_FROM_BRIGHTNESS_KEY +import androidx.test.filters.FlakyTest import androidx.test.filters.SmallTest import androidx.test.rule.ActivityTestRule import com.android.systemui.SysuiTestCase @@ -183,6 +184,7 @@ class BrightnessDialogTest : SysuiTestCase() { } @OptIn(FlowPreview::class) + @FlakyTest(bugId = 326186573) @Test fun testFinishOnQSExpanded() = runTest { val isQSExpanded = MutableStateFlow(false) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 950a9dbc2ff3..fd7b1399d03f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -599,6 +599,8 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { // Primary Bouncer->Gone when(mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha()) .thenReturn(emptyFlow()); + when(mPrimaryBouncerToGoneTransitionViewModel.getNotificationAlpha()) + .thenReturn(emptyFlow()); NotificationsKeyguardViewStateRepository notifsKeyguardViewStateRepository = new NotificationsKeyguardViewStateRepository(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt index 7737b4313e3c..651006dfc953 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt @@ -1,15 +1,46 @@ +@file:OptIn(ExperimentalCoroutinesApi::class) + package com.android.systemui.shade.transition +import android.platform.test.annotations.DisableFlags import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_SCENE_CONTAINER import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository +import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository +import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor +import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor import com.android.systemui.dump.DumpManager +import com.android.systemui.flags.EnableSceneContainer +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.domain.interactor.PanelExpansionInteractor +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.FakeSceneDataSource +import com.android.systemui.scene.shared.model.ObservableTransitionState +import com.android.systemui.scene.shared.model.SceneKey +import com.android.systemui.scene.shared.model.fakeSceneDataSource import com.android.systemui.shade.STATE_OPENING import com.android.systemui.shade.ShadeExpansionChangeEvent import com.android.systemui.shade.ShadeExpansionStateManager import com.android.systemui.statusbar.SysuiStatusBarStateController +import com.android.systemui.statusbar.notification.stack.ui.viewmodel.panelExpansionInteractor import com.android.systemui.statusbar.policy.FakeConfigurationController import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController +import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -29,32 +60,95 @@ class ShadeTransitionControllerTest : SysuiTestCase() { private val configurationController = FakeConfigurationController() private val shadeExpansionStateManager = ShadeExpansionStateManager() + private val kosmos = testKosmos() + private lateinit var testScope: TestScope + private lateinit var applicationScope: CoroutineScope + private lateinit var panelExpansionInteractor: PanelExpansionInteractor + private lateinit var deviceEntryRepository: FakeDeviceEntryRepository + private lateinit var deviceUnlockedInteractor: DeviceUnlockedInteractor + private lateinit var sceneInteractor: SceneInteractor + private lateinit var fakeSceneDataSource: FakeSceneDataSource @Before fun setUp() { MockitoAnnotations.initMocks(this) + testScope = kosmos.testScope + applicationScope = kosmos.applicationCoroutineScope + panelExpansionInteractor = kosmos.panelExpansionInteractor + deviceEntryRepository = kosmos.fakeDeviceEntryRepository + deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor + sceneInteractor = kosmos.sceneInteractor + fakeSceneDataSource = kosmos.fakeSceneDataSource + controller = ShadeTransitionController( + applicationScope, configurationController, shadeExpansionStateManager, dumpManager, context, scrimShadeTransitionController, statusBarStateController, - ResourcesSplitShadeStateController() - ) + ResourcesSplitShadeStateController(), + ) { + panelExpansionInteractor + } } @Test + @DisableFlags(FLAG_SCENE_CONTAINER) fun onPanelStateChanged_forwardsToScrimTransitionController() { - startPanelExpansion() + startLegacyPanelExpansion() verify(scrimShadeTransitionController).onPanelStateChanged(STATE_OPENING) verify(scrimShadeTransitionController).onPanelExpansionChanged(DEFAULT_EXPANSION_EVENT) } - private fun startPanelExpansion() { + @Test + @EnableSceneContainer + fun sceneChanges_forwardsToScrimTransitionController() = + testScope.runTest { + var latestChangeEvent: ShadeExpansionChangeEvent? = null + whenever(scrimShadeTransitionController.onPanelExpansionChanged(any())).thenAnswer { + latestChangeEvent = it.arguments[0] as ShadeExpansionChangeEvent + Unit + } + setUnlocked(true) + val transitionState = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Idle(SceneKey.Gone) + ) + sceneInteractor.setTransitionState(transitionState) + + changeScene(SceneKey.Gone, transitionState) + val currentScene by collectLastValue(sceneInteractor.currentScene) + assertThat(currentScene).isEqualTo(SceneKey.Gone) + + assertThat(latestChangeEvent) + .isEqualTo( + ShadeExpansionChangeEvent( + fraction = 0f, + expanded = false, + tracking = true, + dragDownPxAmount = 0f, + ) + ) + + changeScene(SceneKey.Shade, transitionState) { progress -> + assertThat(latestChangeEvent) + .isEqualTo( + ShadeExpansionChangeEvent( + fraction = progress, + expanded = progress > 0, + tracking = true, + dragDownPxAmount = 0f, + ) + ) + } + } + + private fun startLegacyPanelExpansion() { shadeExpansionStateManager.onPanelExpansionChanged( DEFAULT_EXPANSION_EVENT.fraction, DEFAULT_EXPANSION_EVENT.expanded, @@ -63,6 +157,52 @@ class ShadeTransitionControllerTest : SysuiTestCase() { ) } + private fun TestScope.setUnlocked(isUnlocked: Boolean) { + val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked) + deviceEntryRepository.setUnlocked(isUnlocked) + runCurrent() + + assertThat(isDeviceUnlocked).isEqualTo(isUnlocked) + } + + private fun TestScope.changeScene( + toScene: SceneKey, + transitionState: MutableStateFlow<ObservableTransitionState>, + assertDuringProgress: ((progress: Float) -> Unit) = {}, + ) { + val currentScene by collectLastValue(sceneInteractor.currentScene) + val progressFlow = MutableStateFlow(0f) + transitionState.value = + ObservableTransitionState.Transition( + fromScene = checkNotNull(currentScene), + toScene = toScene, + progress = progressFlow, + isInitiatedByUserInput = true, + isUserInputOngoing = flowOf(true), + ) + runCurrent() + assertDuringProgress(progressFlow.value) + + progressFlow.value = 0.2f + runCurrent() + assertDuringProgress(progressFlow.value) + + progressFlow.value = 0.6f + runCurrent() + assertDuringProgress(progressFlow.value) + + progressFlow.value = 1f + runCurrent() + assertDuringProgress(progressFlow.value) + + transitionState.value = ObservableTransitionState.Idle(toScene) + fakeSceneDataSource.changeScene(toScene) + runCurrent() + assertDuringProgress(progressFlow.value) + + assertThat(currentScene).isEqualTo(toScene) + } + companion object { private const val DEFAULT_DRAG_DOWN_AMOUNT = 123f private val DEFAULT_EXPANSION_EVENT = @@ -70,6 +210,7 @@ class ShadeTransitionControllerTest : SysuiTestCase() { fraction = 0.5f, expanded = true, tracking = true, - dragDownPxAmount = DEFAULT_DRAG_DOWN_AMOUNT) + dragDownPxAmount = DEFAULT_DRAG_DOWN_AMOUNT + ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java index 460892af1154..660e8da72bf1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java @@ -49,6 +49,7 @@ import android.window.TransitionInfo; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.animation.RemoteAnimationTargetCompat; import com.android.wm.shell.shared.TransitionUtil; import org.junit.Before; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt index b958f35c0e53..a41bc0d87615 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryTest.kt @@ -616,7 +616,7 @@ fun validMobileEvent( dataType: SignalIcon.MobileIconGroup? = THREE_G, subId: Int? = 1, carrierId: Int? = UNKNOWN_CARRIER_ID, - inflateStrength: Boolean? = false, + inflateStrength: Boolean = false, activity: Int? = null, carrierNetworkChange: Boolean = false, roaming: Boolean = false, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt index d465b47e93b9..c07f289dd4fd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt @@ -239,7 +239,9 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() { // WHEN all of the connections are OOS i1.isInService.value = false + i1.isEmergencyOnly.value = false i2.isInService.value = false + i2.isEmergencyOnly.value = false // THEN the value is propagated to this interactor assertThat(latest).isTrue() @@ -256,6 +258,7 @@ class DeviceBasedSatelliteInteractorTest : SysuiTestCase() { // WHEN all of the connections are OOS i1.isInService.value = false + i1.isEmergencyOnly.value = false // THEN the value is propagated to this interactor assertThat(latest).isTrue() diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt index cd0652e53657..ec6642de839d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModelTest.kt @@ -80,6 +80,7 @@ class DeviceBasedSatelliteViewModelTest : SysuiTestCase() { // GIVEN all icons are OOS val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1) i1.isInService.value = false + i1.isEmergencyOnly.value = false // GIVEN apm is disabled airplaneModeRepository.setIsAirplaneMode(false) @@ -99,6 +100,7 @@ class DeviceBasedSatelliteViewModelTest : SysuiTestCase() { // GIVEN all icons are not OOS val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1) i1.isInService.value = true + i1.isEmergencyOnly.value = false // GIVEN apm is disabled airplaneModeRepository.setIsAirplaneMode(false) @@ -108,6 +110,35 @@ class DeviceBasedSatelliteViewModelTest : SysuiTestCase() { } @Test + fun icon_nullWhenShouldNotShow_isEmergencyOnly() = + testScope.runTest { + val latest by collectLastValue(underTest.icon) + + // GIVEN satellite is allowed + repo.isSatelliteAllowedForCurrentLocation.value = true + + // GIVEN all icons are OOS + val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1) + i1.isInService.value = false + i1.isEmergencyOnly.value = false + + // GIVEN apm is disabled + airplaneModeRepository.setIsAirplaneMode(false) + + // Wait for delay to be completed + advanceTimeBy(10.seconds) + + // THEN icon is set because we don't have service + assertThat(latest).isInstanceOf(Icon::class.java) + + // GIVEN the connection is emergency only + i1.isEmergencyOnly.value = true + + // THEN icon is null because we have emergency connection + assertThat(latest).isNull() + } + + @Test fun icon_nullWhenShouldNotShow_apmIsEnabled() = testScope.runTest { val latest by collectLastValue(underTest.icon) @@ -118,6 +149,7 @@ class DeviceBasedSatelliteViewModelTest : SysuiTestCase() { // GIVEN all icons are OOS val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1) i1.isInService.value = false + i1.isEmergencyOnly.value = false // GIVEN apm is enabled airplaneModeRepository.setIsAirplaneMode(true) @@ -138,6 +170,7 @@ class DeviceBasedSatelliteViewModelTest : SysuiTestCase() { // GIVEN all icons are OOS val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1) i1.isInService.value = false + i1.isEmergencyOnly.value = false // GIVEN apm is disabled airplaneModeRepository.setIsAirplaneMode(false) @@ -161,6 +194,7 @@ class DeviceBasedSatelliteViewModelTest : SysuiTestCase() { // GIVEN all icons are OOS val i1 = mobileIconsInteractor.getMobileConnectionInteractorForSubId(1) i1.isInService.value = false + i1.isEmergencyOnly.value = false // GIVEN apm is disabled airplaneModeRepository.setIsAirplaneMode(false) diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java index 766a5ce322bf..5d341207ef6a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java @@ -200,4 +200,25 @@ public class ObservableServiceConnectionTest extends SysuiTestCase { assertThat(connection.bind()).isFalse(); verify(mContext).unbindService(connection); } + + @Test + public void testUnbindDoesNotCallUnbindServiceWhenBindThrowsError() { + ObservableServiceConnection<Foo> connection = new ObservableServiceConnection<>(mContext, + mIntent, mUserTracker, mExecutor, mTransformer); + connection.addCallback(mCallback); + + when(mContext.bindServiceAsUser(eq(mIntent), eq(connection), anyInt(), + eq(UserHandle.of(MAIN_USER_ID)))) + .thenThrow(new SecurityException()); + + // Verify that bind returns false and we properly unbind. + assertThat(connection.bind()).isFalse(); + verify(mContext).unbindService(connection); + + clearInvocations(mContext); + + // Ensure unbind after the failed bind has no effect. + connection.unbind(); + verify(mContext, never()).unbindService(eq(connection)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java index 23a9207ec643..ed07ad2a0976 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java @@ -21,21 +21,40 @@ import static org.junit.Assert.assertTrue; import android.os.Build; import android.os.PowerManager; +import android.platform.test.flag.junit.FlagsParameterization; +import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; +import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import org.junit.After; +import org.junit.Assume; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.List; @SmallTest -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) public class WakeLockTest extends SysuiTestCase { + @Parameterized.Parameters(name = "{0}") + public static List<FlagsParameterization> getFlags() { + return FlagsParameterization.allCombinationsOf( + Flags.FLAG_DELAYED_WAKELOCK_RELEASE_ON_BACKGROUND_THREAD); + } + + @Rule public final SetFlagsRule mSetFlagsRule; + + public WakeLockTest(FlagsParameterization flags) { + mSetFlagsRule = new SetFlagsRule(SetFlagsRule.DefaultInitValueType.NULL_DEFAULT, flags); + } + private static final String WHY = "test"; WakeLock mWakeLock; PowerManager.WakeLock mInner; @@ -91,10 +110,7 @@ public class WakeLockTest extends SysuiTestCase { @Test public void prodBuild_wakeLock_releaseWithoutAcquire_noThrow() { - if (Build.IS_ENG) { - return; - } - + Assume.assumeFalse(Build.IS_ENG); // shouldn't throw an exception on production builds mWakeLock.release(WHY); } 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 d2e03861b022..3a6324d3de53 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -61,7 +61,6 @@ import android.widget.ImageButton; import android.widget.SeekBar; import androidx.test.core.view.MotionEventBuilder; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.internal.jank.InteractionJankMonitor; @@ -502,7 +501,6 @@ public class VolumeDialogImplTest extends SysuiTestCase { } @Test - @FlakyTest(bugId = 326204750) public void dialogDestroy_removesPostureControllerCallback() { verify(mPostureController, never()).removeCallback(any()); mDialog.destroy(); diff --git a/packages/SystemUI/tests/utils/src/android/content/ContextKosmos.kt b/packages/SystemUI/tests/utils/src/android/content/ContextKosmos.kt index f6ddfccfa532..185deea31747 100644 --- a/packages/SystemUI/tests/utils/src/android/content/ContextKosmos.kt +++ b/packages/SystemUI/tests/utils/src/android/content/ContextKosmos.kt @@ -20,5 +20,6 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testCase import com.android.systemui.util.mockito.mock -var Kosmos.applicationContext: Context by Kosmos.Fixture { testCase.context } +var Kosmos.applicationContext: Context by + Kosmos.Fixture { testCase.context.apply { ensureTestableResources() } } val Kosmos.mockedContext: Context by Kosmos.Fixture { mock<Context>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/assist/data/repository/AssistRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/assist/data/repository/AssistRepositoryKosmos.kt new file mode 100644 index 000000000000..96155ed1ec9f --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/assist/data/repository/AssistRepositoryKosmos.kt @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.assist.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.assistRepository by Kosmos.Fixture { AssistRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/assist/domain/interactor/AssistInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/assist/domain/interactor/AssistInteractorKosmos.kt new file mode 100644 index 000000000000..c3c11318b0cc --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/assist/domain/interactor/AssistInteractorKosmos.kt @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.assist.domain.interactor + +import com.android.systemui.assist.data.repository.assistRepository +import com.android.systemui.kosmos.Kosmos + +val Kosmos.assistInteractor by Kosmos.Fixture { AssistInteractor(assistRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt index 77f501f550d7..68ef55573dc8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt @@ -33,6 +33,10 @@ class FakeFacePropertyRepository : FacePropertyRepository { override val sensorLocation: StateFlow<Point?> get() = faceSensorLocation + private val currentCameraInfo = MutableStateFlow<CameraInfo?>(null) + override val cameraInfo: StateFlow<CameraInfo?> + get() = currentCameraInfo + fun setLockoutMode(userId: Int, mode: LockoutMode) { lockoutModesForUser[userId] = mode } @@ -47,4 +51,8 @@ class FakeFacePropertyRepository : FacePropertyRepository { fun setSensorLocation(value: Point?) { faceSensorLocation.value = value } + + fun setCameraIno(value: CameraInfo?) { + currentCameraInfo.value = value + } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java index 5038285aef00..974a11cfaf77 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java @@ -201,4 +201,13 @@ public class FalsingManagerFake implements FalsingManager { public List<FalsingTapListener> getTapListeners() { return mTapListeners; } + + /** + * Calls every registered {@link FalsingBeliefListener} as if false touch occurred. + */ + public void sendFalsingBelief() { + for (FalsingBeliefListener listener : mFalsingBeliefListeners) { + listener.onFalse(); + } + } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt index 55885bf58acc..5dd50731c58a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt @@ -19,13 +19,11 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.kosmos.testDispatcher val Kosmos.glanceableHubTransitions by Kosmos.Fixture { GlanceableHubTransitions( - scope = applicationCoroutineScope, bgDispatcher = testDispatcher, transitionRepository = keyguardTransitionRepository, transitionInteractor = keyguardTransitionInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..c6f07068aad4 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@ExperimentalCoroutinesApi +val Kosmos.alternateBouncerToDozingTransitionViewModel by Fixture { + AlternateBouncerToDozingTransitionViewModel( + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..36ddc29b8914 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@ExperimentalCoroutinesApi +val Kosmos.dozingToGoneTransitionViewModel by Fixture { + DozingToGoneTransitionViewModel( + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt index 400a0d87f041..de52d848e94b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow @@ -23,6 +21,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import kotlinx.coroutines.ExperimentalCoroutinesApi +@ExperimentalCoroutinesApi val Kosmos.dozingToLockscreenTransitionViewModel by Fixture { DozingToLockscreenTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..dc6b26feac15 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@ExperimentalCoroutinesApi +val Kosmos.dozingToPrimaryBouncerTransitionViewModel by Fixture { + DozingToPrimaryBouncerTransitionViewModel( + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt index b37085957d7e..00741eb69c62 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt @@ -16,12 +16,14 @@ package com.android.systemui.keyguard.ui.viewmodel +import com.android.systemui.common.ui.domain.interactor.configurationInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos val Kosmos.dreamingToGlanceableHubTransitionViewModel by Kosmos.Fixture { DreamingToGlanceableHubTransitionViewModel( + configurationInteractor = configurationInteractor, animationFlow = keyguardTransitionAnimationFlow, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt index 8b5407cc7e17..5f70a2f06f2e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt @@ -14,11 +14,8 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos @@ -26,11 +23,11 @@ import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.util.mockito.mock import kotlinx.coroutines.ExperimentalCoroutinesApi +@ExperimentalCoroutinesApi val Kosmos.dreamingToLockscreenTransitionViewModel by Fixture { DreamingToLockscreenTransitionViewModel( keyguardTransitionInteractor = keyguardTransitionInteractor, fromDreamingTransitionInteractor = mock(), - deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, animationFlow = keyguardTransitionAnimationFlow, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..1302f155d93b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.common.ui.domain.interactor.configurationInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos + +val Kosmos.glanceableHubToDreamingTransitionViewModel by + Kosmos.Fixture { + GlanceableHubToDreamingTransitionViewModel( + configurationInteractor = configurationInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt index 4daf46028979..b19d4e87e68c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt @@ -14,17 +14,18 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import kotlinx.coroutines.ExperimentalCoroutinesApi +@ExperimentalCoroutinesApi val Kosmos.goneToDozingTransitionViewModel by Fixture { GoneToDozingTransitionViewModel( + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, animationFlow = keyguardTransitionAnimationFlow, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt index ecf66a297f0d..8ca53e6591c0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt @@ -42,6 +42,10 @@ val Kosmos.keyguardRootViewModel by Fixture { aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel, dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel, glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel, + goneToAodTransitionViewModel = goneToAodTransitionViewModel, + goneToDozingTransitionViewModel = goneToDozingTransitionViewModel, + lockscreenToAodTransitionViewModel = lockscreenToAodTransitionViewModel, + lockscreenToDozingTransitionViewModel = lockscreenToDozingTransitionViewModel, lockscreenToDreamingTransitionViewModel = lockscreenToDreamingTransitionViewModel, lockscreenToGlanceableHubTransitionViewModel = lockscreenToGlanceableHubTransitionViewModel, lockscreenToGoneTransitionViewModel = lockscreenToGoneTransitionViewModel, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..aa8e9a8c9a8c --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@ExperimentalCoroutinesApi +val Kosmos.lockscreenToDozingTransitionViewModel by Fixture { + LockscreenToDozingTransitionViewModel( + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt index 1b2337fedf6a..17c3a14bd5e1 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt @@ -14,8 +14,6 @@ * limitations under the License. */ -@file:OptIn(ExperimentalCoroutinesApi::class) - package com.android.systemui.keyguard.ui.viewmodel import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow @@ -23,6 +21,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import kotlinx.coroutines.ExperimentalCoroutinesApi +@ExperimentalCoroutinesApi val Kosmos.lockscreenToGoneTransitionViewModel by Fixture { LockscreenToGoneTransitionViewModel( animationFlow = keyguardTransitionAnimationFlow, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt new file mode 100644 index 000000000000..d4e4b8c34807 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.ui.viewmodel + +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@ExperimentalCoroutinesApi +val Kosmos.primaryBouncerToDozingTransitionViewModel by Fixture { + PrimaryBouncerToDozingTransitionViewModel( + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + animationFlow = keyguardTransitionAnimationFlow, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/SpatializerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/SpatializerKosmos.kt new file mode 100644 index 000000000000..7001ea8b6427 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/SpatializerKosmos.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.media + +import com.android.settingslib.media.domain.interactor.SpatializerInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.media.data.repository.FakeSpatializerRepository + +val Kosmos.spatializerRepository by Kosmos.Fixture { FakeSpatializerRepository() } +val Kosmos.spatializerInteractor by Kosmos.Fixture { SpatializerInteractor(spatializerRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/data/repository/FakeSpatializerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/data/repository/FakeSpatializerRepository.kt new file mode 100644 index 000000000000..0183b97090dc --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/data/repository/FakeSpatializerRepository.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.media.data.repository + +import android.media.AudioDeviceAttributes +import com.android.settingslib.media.data.repository.SpatializerRepository +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +class FakeSpatializerRepository : SpatializerRepository { + + var defaultSpatialAudioAvailable: Boolean = false + + private val spatialAudioAvailabilityByDevice: MutableMap<AudioDeviceAttributes, Boolean> = + mutableMapOf() + private val spatialAudioCompatibleDevices: MutableList<AudioDeviceAttributes> = mutableListOf() + + private val mutableHeadTrackingAvailable = MutableStateFlow(false) + private val headTrackingEnabledByDevice = mutableMapOf<AudioDeviceAttributes, Boolean>() + + override val isHeadTrackingAvailable: StateFlow<Boolean> = + mutableHeadTrackingAvailable.asStateFlow() + + override suspend fun isSpatialAudioAvailableForDevice( + audioDeviceAttributes: AudioDeviceAttributes + ): Boolean = + spatialAudioAvailabilityByDevice.getOrDefault( + audioDeviceAttributes, + defaultSpatialAudioAvailable + ) + + override suspend fun getSpatialAudioCompatibleDevices(): Collection<AudioDeviceAttributes> = + spatialAudioCompatibleDevices + + override suspend fun addSpatialAudioCompatibleDevice( + audioDeviceAttributes: AudioDeviceAttributes + ) { + spatialAudioCompatibleDevices.add(audioDeviceAttributes) + } + + override suspend fun removeSpatialAudioCompatibleDevice( + audioDeviceAttributes: AudioDeviceAttributes + ) { + spatialAudioCompatibleDevices.remove(audioDeviceAttributes) + } + + override suspend fun isHeadTrackingEnabled( + audioDeviceAttributes: AudioDeviceAttributes + ): Boolean = headTrackingEnabledByDevice.getOrDefault(audioDeviceAttributes, false) + + override suspend fun setHeadTrackingEnabled( + audioDeviceAttributes: AudioDeviceAttributes, + isEnabled: Boolean + ) { + headTrackingEnabledByDevice[audioDeviceAttributes] = isEnabled + } + + fun setIsSpatialAudioAvailable( + audioDeviceAttributes: AudioDeviceAttributes, + isAvailable: Boolean, + ) { + spatialAudioAvailabilityByDevice[audioDeviceAttributes] = isAvailable + } + + fun setIsHeadTrackingAvailable(isAvailable: Boolean) { + mutableHeadTrackingAvailable.value = isAvailable + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/PanelExpansionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/PanelExpansionInteractorKosmos.kt new file mode 100644 index 000000000000..a025846f74a3 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/PanelExpansionInteractorKosmos.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.stack.ui.viewmodel + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.scene.domain.interactor.PanelExpansionInteractor +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.shade.data.repository.shadeRepository + +val Kosmos.panelExpansionInteractor by Fixture { + PanelExpansionInteractor( + sceneInteractor = sceneInteractor, + shadeRepository = shadeRepository, + ) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt index c01032757bb0..11acf1c9ff64 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt @@ -60,6 +60,8 @@ class FakeMobileIconInteractor( override val isInService = MutableStateFlow(true) + override val isEmergencyOnly = MutableStateFlow(true) + override val isNonTerrestrial = MutableStateFlow(false) private val _isDataEnabled = MutableStateFlow(true) diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp index 53897e14ecd6..41a4a1ad1ccb 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -47,6 +47,7 @@ java_library { ], libs: [ "framework-minus-apex.ravenwood", + "ravenwood-junit", ], visibility: ["//visibility:private"], } diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt index 6b6736476210..371c3acab144 100644 --- a/ravenwood/framework-minus-apex-ravenwood-policies.txt +++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt @@ -55,3 +55,5 @@ class android.content.Context stub method getSystemService (Ljava/lang/Class;)Ljava/lang/Object; stub class android.content.pm.PackageManager stub method <init> ()V stub +class android.text.ClipboardManager stub + method <init> ()V stub diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java index 3668b03e58d3..c17d0903f856 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java @@ -16,18 +16,28 @@ package android.platform.test.ravenwood; +import android.content.ClipboardManager; import android.content.Context; import android.hardware.ISerialManager; import android.hardware.SerialManager; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; import android.os.PermissionEnforcer; import android.os.ServiceManager; +import android.os.UserHandle; import android.test.mock.MockContext; import android.util.ArrayMap; import android.util.Singleton; +import java.util.Objects; +import java.util.concurrent.Executor; import java.util.function.Supplier; public class RavenwoodContext extends MockContext { + private final String mPackageName; + private final HandlerThread mMainThread; + private final RavenwoodPermissionEnforcer mEnforcer = new RavenwoodPermissionEnforcer(); private final ArrayMap<Class<?>, String> mClassToName = new ArrayMap<>(); @@ -39,7 +49,13 @@ public class RavenwoodContext extends MockContext { mNameToFactory.put(serviceName, serviceSupplier); } - public RavenwoodContext() { + public RavenwoodContext(String packageName, HandlerThread mainThread) { + mPackageName = packageName; + mMainThread = mainThread; + + registerService(ClipboardManager.class, + Context.CLIPBOARD_SERVICE, asSingleton(() -> + new ClipboardManager(this, getMainThreadHandler()))); registerService(PermissionEnforcer.class, Context.PERMISSION_ENFORCER_SERVICE, () -> mEnforcer); registerService(SerialManager.class, @@ -73,18 +89,79 @@ public class RavenwoodContext extends MockContext { } } + @Override + public Looper getMainLooper() { + Objects.requireNonNull(mMainThread, + "Test must request setProvideMainThread() via RavenwoodRule"); + return mMainThread.getLooper(); + } + + @Override + public Handler getMainThreadHandler() { + Objects.requireNonNull(mMainThread, + "Test must request setProvideMainThread() via RavenwoodRule"); + return mMainThread.getThreadHandler(); + } + + @Override + public Executor getMainExecutor() { + Objects.requireNonNull(mMainThread, + "Test must request setProvideMainThread() via RavenwoodRule"); + return mMainThread.getThreadExecutor(); + } + + @Override + public String getPackageName() { + return Objects.requireNonNull(mPackageName, + "Test must request setPackageName() via RavenwoodRule"); + } + + @Override + public String getOpPackageName() { + return Objects.requireNonNull(mPackageName, + "Test must request setPackageName() via RavenwoodRule"); + } + + @Override + public String getAttributionTag() { + return null; + } + + @Override + public UserHandle getUser() { + return android.os.UserHandle.of(android.os.UserHandle.myUserId()); + } + + @Override + public int getUserId() { + return android.os.UserHandle.myUserId(); + } + + @Override + public int getDeviceId() { + return Context.DEVICE_ID_DEFAULT; + } + /** * Wrap the given {@link Supplier} to become a memoized singleton. */ - private static <T> Supplier<T> asSingleton(Supplier<T> supplier) { + private static <T> Supplier<T> asSingleton(ThrowingSupplier<T> supplier) { final Singleton<T> singleton = new Singleton<>() { @Override protected T create() { - return supplier.get(); + try { + return supplier.get(); + } catch (Exception e) { + throw new RuntimeException(e); + } } }; return () -> { return singleton.get(); }; } + + public interface ThrowingSupplier<T> { + T get() throws Exception; + } } diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java index 231cce95f353..56a3c64a5750 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java @@ -110,13 +110,16 @@ public class RavenwoodRuleImpl { ActivityManager.init$ravenwood(rule.mCurrentUser); + final HandlerThread main; if (rule.mProvideMainThread) { - final HandlerThread main = new HandlerThread(MAIN_THREAD_NAME); + main = new HandlerThread(MAIN_THREAD_NAME); main.start(); Looper.setMainLooperForTest(main.getLooper()); + } else { + main = null; } - rule.mContext = new RavenwoodContext(); + rule.mContext = new RavenwoodContext(rule.mPackageName, main); rule.mInstrumentation = new Instrumentation(); rule.mInstrumentation.basicInit(rule.mContext); InstrumentationRegistry.registerInstance(rule.mInstrumentation, Bundle.EMPTY); diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java index bb280f47ccd9..3de96c0990ea 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java @@ -16,6 +16,7 @@ package android.platform.test.ravenwood; +import android.content.ClipboardManager; import android.hardware.SerialManager; import android.os.SystemClock; import android.util.ArrayMap; @@ -40,7 +41,10 @@ public class RavenwoodSystemServer { // authors to exhaustively declare all transitive services static { - sKnownServices.put(SerialManager.class, "com.android.server.SerialService$Lifecycle"); + sKnownServices.put(ClipboardManager.class, + "com.android.server.FakeClipboardService$Lifecycle"); + sKnownServices.put(SerialManager.class, + "com.android.server.SerialService$Lifecycle"); } private static TimingsTraceAndSlog sTimings; diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java index a8c24fcbd7e0..a520d4ccafa1 100644 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java @@ -121,6 +121,8 @@ public class RavenwoodRule implements TestRule { int mUid = NOBODY_UID; int mPid = sNextPid.getAndIncrement(); + String mPackageName; + boolean mProvideMainThread = false; final RavenwoodSystemProperties mSystemProperties = new RavenwoodSystemProperties(); @@ -158,6 +160,15 @@ public class RavenwoodRule implements TestRule { } /** + * Configure the identity of this process to be the given package name for the duration + * of the test. Has no effect on non-Ravenwood environments. + */ + public Builder setPackageName(/* @NonNull */ String packageName) { + mRule.mPackageName = Objects.requireNonNull(packageName); + return this; + } + + /** * Configure a "main" thread to be available for the duration of the test, as defined * by {@code Looper.getMainLooper()}. Has no effect on non-Ravenwood environments. */ diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java index b736a7662bd4..37ceac601e37 100644 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java @@ -73,9 +73,9 @@ public class RavenwoodUtils { return; } } - throw new UnsatisfiedLinkError("Library " + libname + " no found in " + throw new UnsatisfiedLinkError("Library " + libname + " not found in " + "java.library.path: " + path); - } catch (Exception e) { + } catch (Throwable e) { dumpFiles(System.out); throw e; } @@ -96,6 +96,10 @@ public class RavenwoodUtils { listFiles(out, gparent, ""); } } + + var gparent = new File("../..").getCanonicalFile(); + out.println("# ../..=" + gparent); + listFiles(out, gparent, ""); } catch (Throwable th) { out.println("Error: " + th.toString()); th.printStackTrace(out); diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt index eb3c55cb4ff6..9b4d378cc7b7 100644 --- a/ravenwood/ravenwood-annotation-allowed-classes.txt +++ b/ravenwood/ravenwood-annotation-allowed-classes.txt @@ -186,6 +186,7 @@ android.os.WorkSource android.content.ClipData android.content.ClipData$Item android.content.ClipDescription +android.content.ClipboardManager android.content.ComponentName android.content.ContentUris android.content.ContentValues diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java index 5930a14cdec8..f301b9c46b0e 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java +++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java @@ -22,6 +22,13 @@ import com.android.internal.os.RuntimeInit; import java.io.PrintStream; +/** + * Ravenwood "native substitution" class for {@link android.util.Log}. + * + * {@link android.util.Log} already uses the actual native code and doesn't use this class. + * In order to switch to this Java implementation, uncomment the @RavenwoodNativeSubstitutionClass + * annotation on {@link android.util.Log}. + */ public class Log_host { public static boolean isLoggable(String tag, @Level int level) { diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java index 1e120305fa2d..cc94090d9ec7 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java +++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java @@ -15,8 +15,9 @@ */ package com.android.platform.test.ravenwood.runtimehelper; +import android.platform.test.ravenwood.RavenwoodUtils; + import java.io.File; -import java.io.PrintStream; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -27,8 +28,6 @@ import java.util.ArrayList; * load other JNI or do other set up here. */ public class ClassLoadHook { - private static PrintStream sOut = System.out; - /** * If true, we won't load `libandroid_runtime` * @@ -36,7 +35,7 @@ public class ClassLoadHook { * so we need a way to remove the dependency. */ private static final boolean SKIP_LOADING_LIBANDROID = "1".equals(System.getenv( - "HOSTTEST_SKIP_LOADING_LIBANDROID")); + "RAVENWOOD_SKIP_LOADING_LIBANDROID")); public static final String CORE_NATIVE_CLASSES = "core_native_classes"; public static final String ICU_DATA_PATH = "icu.data.path"; @@ -44,7 +43,7 @@ public class ClassLoadHook { public static final String GRAPHICS_NATIVE_CLASSES = "graphics_native_classes"; public static final String VALUE_N_A = "**n/a**"; - public static final String LIBANDROID_RUNTIME_NAME = "libandroid_runtime"; + public static final String LIBANDROID_RUNTIME_NAME = "android_runtime"; private static String sInitialDir = new File("").getAbsolutePath(); @@ -68,7 +67,7 @@ public class ClassLoadHook { } private static void log(String message) { - sOut.println("ClassLoadHook: " + message); + System.out.println("ClassLoadHook: " + message); } private static void log(String fmt, Object... args) { @@ -92,13 +91,6 @@ public class ClassLoadHook { } } - private static void loadJniLibrary(String name) { - final String path = sInitialDir + "/lib64/" + name + ".so"; - System.out.println("Loading " + path + " ..."); - System.load(path); - System.out.println("Done loading " + path); - } - private static boolean sLoadFrameworkNativeCodeCalled = false; /** @@ -115,7 +107,7 @@ public class ClassLoadHook { // libandroid_runtime uses Java's system properties to decide what JNI methods to set up. // Set up these properties for host-side tests. - if ("1".equals(System.getenv("HOSTTEST_DUMP_PROPERTIES"))) { + if ("1".equals(System.getenv("RAVENWOOD_DUMP_PROPERTIES"))) { log("Java system properties:"); dumpSystemProperties(); } @@ -141,7 +133,7 @@ public class ClassLoadHook { setProperty(ICU_DATA_PATH, VALUE_N_A); setProperty(KEYBOARD_PATHS, VALUE_N_A); - loadJniLibrary(LIBANDROID_RUNTIME_NAME); + RavenwoodUtils.loadJniLibrary(LIBANDROID_RUNTIME_NAME); } /** @@ -156,7 +148,7 @@ public class ClassLoadHook { }; /** - * @return if a given method is a native method or not. + * @return if a given class has any native method or not. */ private static boolean hasNativeMethod(Class<?> clazz) { for (var method : clazz.getDeclaredMethods()) { diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java index 67c2caa338a6..e9f6031e5048 100644 --- a/rs/java/android/renderscript/ScriptC.java +++ b/rs/java/android/renderscript/ScriptC.java @@ -38,12 +38,12 @@ public class ScriptC extends Script { private static final String TAG = "ScriptC"; /** - * In targetSdkVersion 35 and above, Renderscript's ScriptC stops being supported + * In targetSdkVersion 36 and above, Renderscript's ScriptC stops being supported * and an exception is thrown when the class is instantiated. - * In targetSdkVersion 34 and below, Renderscript's ScriptC still works. + * In targetSdkVersion 35 and below, Renderscript's ScriptC still works. */ @ChangeId - @EnabledAfter(targetSdkVersion = 35) + @EnabledAfter(targetSdkVersion = 36) private static final long RENDERSCRIPT_SCRIPTC_DEPRECATION_CHANGE_ID = 297019750L; /** @@ -101,9 +101,21 @@ public class ScriptC extends Script { setID(id); } - private static void throwExceptionIfSDKTooHigh() { + private static void throwExceptionIfScriptCUnsupported() { + // Checks that this device actually does have an ABI that supports ScriptC. + // + // For an explanation as to why `System.loadLibrary` is used, see discussion at + // https://android-review.googlesource.com/c/platform/frameworks/base/+/2957974/comment/2f908b80_a05292ee + try { + System.loadLibrary("RS"); + } catch (UnsatisfiedLinkError e) { + String s = "This device does not have an ABI that supports ScriptC."; + throw new UnsupportedOperationException(s); + } + + // Throw an exception if the target API is 36 or above String message = - "ScriptC scripts are not supported when targeting an API Level >= 35. Please refer " + "ScriptC scripts are not supported when targeting an API Level >= 36. Please refer " + "to https://developer.android.com/guide/topics/renderscript/migration-guide " + "for proposed alternatives."; Slog.w(TAG, message); @@ -113,7 +125,7 @@ public class ScriptC extends Script { } private static synchronized long internalCreate(RenderScript rs, Resources resources, int resourceID) { - throwExceptionIfSDKTooHigh(); + throwExceptionIfScriptCUnsupported(); byte[] pgm; int pgmLength; InputStream is = resources.openRawResource(resourceID); @@ -150,7 +162,7 @@ public class ScriptC extends Script { private static synchronized long internalStringCreate(RenderScript rs, String resName, byte[] bitcode) { // Log.v(TAG, "Create script for resource = " + resName); - throwExceptionIfSDKTooHigh(); + throwExceptionIfScriptCUnsupported(); return rs.nScriptCCreate(resName, RenderScript.getCachePath(), bitcode, bitcode.length); } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 16119d11ee1e..54e545d6d73a 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -16,6 +16,8 @@ package com.android.server.accessibility; +import static android.view.InputDevice.SOURCE_CLASS_POINTER; +import static android.view.MotionEvent.ACTION_SCROLL; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY; @@ -425,6 +427,12 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo boolean shouldProcessMultiDeviceEvent(InputEvent event, int policyFlags) { if (event instanceof MotionEvent motion) { + if (!motion.isFromSource(SOURCE_CLASS_POINTER) || motion.getAction() == ACTION_SCROLL) { + // Non-pointer events are focus-dispatched and don't require special logic. + // Scroll events are stand-alone and therefore can be considered to not be part of + // a stream. + return true; + } // Only allow 1 device to be sending motion events at a time // If the event is from an active device, let it through. // If the event is not from an active device, only let it through if it starts a new @@ -481,7 +489,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo } private void processMotionEvent(EventStreamState state, MotionEvent event, int policyFlags) { - if (!state.shouldProcessScroll() && event.getActionMasked() == MotionEvent.ACTION_SCROLL) { + if (!state.shouldProcessScroll() && event.getActionMasked() == ACTION_SCROLL) { super.onInputEvent(event, policyFlags); return; } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 46db624cf3c1..43c018cfeea3 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -3460,13 +3460,20 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (!mMagnificationController.supportWindowMagnification()) { return; } - final boolean connect = (userState.isShortcutMagnificationEnabledLocked() + + final boolean shortcutEnabled = (userState.isShortcutMagnificationEnabledLocked() || userState.isMagnificationSingleFingerTripleTapEnabledLocked() || (Flags.enableMagnificationMultipleFingerMultipleTapGesture() - && userState.isMagnificationTwoFingerTripleTapEnabledLocked())) - && (userState.getMagnificationCapabilitiesLocked() - != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) + && userState.isMagnificationTwoFingerTripleTapEnabledLocked())); + + final boolean createConnectionForCurrentCapability = + com.android.window.flags.Flags.magnificationAlwaysDrawFullscreenBorder() + || (userState.getMagnificationCapabilitiesLocked() + != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN); + + final boolean connect = (shortcutEnabled && createConnectionForCurrentCapability) || userHasMagnificationServicesLocked(userState); + getMagnificationConnectionManager().requestConnection(connect); } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java index e11c36a91830..bc143428e1ae 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java @@ -674,6 +674,23 @@ public class MagnificationConnectionManager implements } /** + * Notify Fullscreen magnification activation changes. + */ + public boolean onFullscreenMagnificationActivationChanged(int displayId, boolean activated) { + synchronized (mLock) { + waitForConnectionIfNeeded(); + if (mConnectionWrapper == null) { + Slog.w(TAG, + "onFullscreenMagnificationActivationChanged mConnectionWrapper is null. " + + "mConnectionState=" + connectionStateToString(mConnectionState)); + return false; + } + return mConnectionWrapper + .onFullscreenMagnificationActivationChanged(displayId, activated); + } + } + + /** * Calculates the number of fingers in the window. * * @param displayId The logical display id. @@ -1267,15 +1284,7 @@ public class MagnificationConnectionManager implements float centerY, float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY, MagnificationAnimationCallback animationCallback) { - // Wait for the connection with a timeout. - final long endMillis = SystemClock.uptimeMillis() + WAIT_CONNECTION_TIMEOUT_MILLIS; - while (mConnectionState == CONNECTING && (SystemClock.uptimeMillis() < endMillis)) { - try { - mLock.wait(endMillis - SystemClock.uptimeMillis()); - } catch (InterruptedException ie) { - /* ignore */ - } - } + waitForConnectionIfNeeded(); if (mConnectionWrapper == null) { Slog.w(TAG, "enableWindowMagnificationInternal mConnectionWrapper is null. " @@ -1317,4 +1326,16 @@ public class MagnificationConnectionManager implements return mConnectionWrapper != null && mConnectionWrapper.moveWindowMagnifierToPosition( displayId, positionX, positionY, animationCallback); } + + private void waitForConnectionIfNeeded() { + // Wait for the connection with a timeout. + final long endMillis = SystemClock.uptimeMillis() + WAIT_CONNECTION_TIMEOUT_MILLIS; + while (mConnectionState == CONNECTING && (SystemClock.uptimeMillis() < endMillis)) { + try { + mLock.wait(endMillis - SystemClock.uptimeMillis()); + } catch (InterruptedException ie) { + /* ignore */ + } + } + } } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java index db5b3133169a..f6fb24f38a7a 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java @@ -58,6 +58,22 @@ class MagnificationConnectionWrapper { mConnection.asBinder().linkToDeath(deathRecipient, 0); } + boolean onFullscreenMagnificationActivationChanged(int displayId, boolean activated) { + if (mTrace.isA11yTracingEnabledForTypes(FLAGS_MAGNIFICATION_CONNECTION)) { + mTrace.logTrace(TAG + ".onFullscreenMagnificationActivationChanged", + FLAGS_MAGNIFICATION_CONNECTION); + } + try { + mConnection.onFullscreenMagnificationActivationChanged(displayId, activated); + } catch (RemoteException e) { + if (DBG) { + Slog.e(TAG, "Error calling onFullscreenMagnificationActivationChanged"); + } + return false; + } + return true; + } + boolean enableWindowMagnification(int displayId, float scale, float centerX, float centerY, float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY, @Nullable MagnificationAnimationCallback callback) { diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java index 52e123a5e70c..0d5fd1435ca0 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java @@ -50,6 +50,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.wm.WindowManagerInternal; +import com.android.window.flags.Flags; import java.util.concurrent.Executor; @@ -586,6 +587,11 @@ public class MagnificationController implements MagnificationConnectionManager.C @Override public void onFullScreenMagnificationActivationState(int displayId, boolean activated) { + if (Flags.magnificationAlwaysDrawFullscreenBorder()) { + getMagnificationConnectionManager() + .onFullscreenMagnificationActivationChanged(displayId, activated); + } + if (activated) { synchronized (mLock) { mFullScreenModeEnabledTimeArray.put(displayId, SystemClock.uptimeMillis()); diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index c4341b9367ec..d779fbf2eabc 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -2802,9 +2802,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final int datasetIdx = AutofillManager.getDatasetIdFromAuthenticationId( authenticationId); + Dataset dataset = null; // Authenticated a dataset - reset view state regardless if we got a response or a dataset if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) { - final Dataset dataset = authenticatedResponse.getDatasets().get(datasetIdx); + dataset = authenticatedResponse.getDatasets().get(datasetIdx); if (dataset == null) { Slog.w(TAG, "no dataset with index " + datasetIdx + " on fill response"); mPresentationStatsEventLogger.maybeSetAuthenticationResult( @@ -2819,12 +2820,29 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mSessionFlags.mExpiredResponse = false; final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT); + final GetCredentialException exception = data.getSerializable( + CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION, + GetCredentialException.class); final Bundle newClientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE); if (sDebug) { Slog.d(TAG, "setAuthenticationResultLocked(): result=" + result + ", clientState=" + newClientState + ", authenticationId=" + authenticationId); } + if (Flags.autofillCredmanDevIntegration() && exception != null + && exception instanceof GetCredentialException) { + if (dataset != null && dataset.getFieldIds().size() == 1) { + if (sDebug) { + Slog.d(TAG, "setAuthenticationResultLocked(): result returns with" + + "Credential Manager Exception"); + } + AutofillId autofillId = dataset.getFieldIds().get(0); + sendCredentialManagerResponseToApp(/*response=*/ null, + (GetCredentialException) exception, autofillId); + } + return; + } + if (result instanceof FillResponse) { if (sDebug) { Slog.d(TAG, "setAuthenticationResultLocked(): received FillResponse from" @@ -2840,13 +2858,21 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } if (Flags.autofillCredmanDevIntegration()) { GetCredentialResponse response = (GetCredentialResponse) result; - sendCredentialManagerResponseToApp(response, - /*exception=*/ null, response.getAutofillId()); + if (dataset != null && dataset.getFieldIds().size() == 1) { + AutofillId autofillId = dataset.getFieldIds().get(0); + if (sDebug) { + Slog.d(TAG, "Received GetCredentialResponse from authentication flow," + + "for autofillId: " + autofillId); + } + sendCredentialManagerResponseToApp(response, + /*exception=*/ null, autofillId); + } } else if (Flags.autofillCredmanIntegration()) { - Dataset dataset = getDatasetFromCredentialResponse( + Dataset datasetFromCredentialResponse = getDatasetFromCredentialResponse( (GetCredentialResponse) result); - if (dataset != null) { - autoFill(requestId, datasetIdx, dataset, false, UI_TYPE_UNKNOWN); + if (datasetFromCredentialResponse != null) { + autoFill(requestId, datasetIdx, datasetFromCredentialResponse, + false, UI_TYPE_UNKNOWN); } } } else if (result instanceof Dataset) { @@ -2863,12 +2889,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (sDebug) Slog.d(TAG, "Updating client state from auth dataset"); mClientState = newClientState; } - Dataset dataset = getEffectiveDatasetForAuthentication((Dataset) result); + Dataset datasetFromResult = getEffectiveDatasetForAuthentication((Dataset) result); final Dataset oldDataset = authenticatedResponse.getDatasets().get(datasetIdx); if (!isAuthResultDatasetEphemeral(oldDataset, data)) { - authenticatedResponse.getDatasets().set(datasetIdx, dataset); + authenticatedResponse.getDatasets().set(datasetIdx, datasetFromResult); } - autoFill(requestId, datasetIdx, dataset, false, UI_TYPE_UNKNOWN); + autoFill(requestId, datasetIdx, datasetFromResult, false, UI_TYPE_UNKNOWN); } else { Slog.w(TAG, "invalid index (" + datasetIdx + ") for authentication id " + authenticationId); @@ -5052,12 +5078,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } private void addCredentialManagerCallbackForDataset(Dataset dataset, int requestId) { + AutofillId autofillId = null; + if (dataset != null && dataset.getFieldIds().size() == 1) { + autofillId = dataset.getFieldIds().get(0); + } + final AutofillId finalAutofillId = autofillId; final ResultReceiver resultReceiver = new ResultReceiver(mHandler) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { if (resultCode == SUCCESS_CREDMAN_SELECTOR) { Slog.d(TAG, "onReceiveResult from Credential Manager bottom sheet"); - boolean isCredmanCallbackInvoked = false; GetCredentialResponse getCredentialResponse = resultData.getParcelable( CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE, @@ -5065,7 +5095,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (Flags.autofillCredmanDevIntegration()) { sendCredentialManagerResponseToApp(getCredentialResponse, - /*exception=*/ null, getCredentialResponse.getAutofillId()); + /*exception=*/ null, finalAutofillId); } else { Dataset datasetFromCredential = getDatasetFromCredentialResponse( getCredentialResponse); @@ -5082,7 +5112,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState Slog.w(TAG, "Credman bottom sheet from pinned " + "entry failed with: + " + exception[0] + " , " + exception[1]); - // TODO(b/326313420): Propagate exception + sendCredentialManagerResponseToApp(/*response=*/ null, + new GetCredentialException(exception[0], exception[1]), + finalAutofillId); } } else { Slog.d(TAG, "Unknown resultCode from credential " @@ -5094,6 +5126,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState toIpcFriendlyResultReceiver(resultReceiver); Intent metadataIntent = dataset.getCredentialFillInIntent(); + if (metadataIntent == null) { + metadataIntent = new Intent(); + } + metadataIntent.putExtra( android.credentials.selection.Constants.EXTRA_FINAL_RESPONSE_RECEIVER, ipcFriendlyResultReceiver); @@ -6380,7 +6416,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } } if (exception != null) { - // TODO(b/326313420): Add Exception support + mClient.onGetCredentialException(id, viewId, exception.getType(), + exception.getMessage()); } else if (response != null) { mClient.onGetCredentialResponse(id, viewId, response); } else { diff --git a/services/companion/java/com/android/server/companion/AssociationRevokeProcessor.java b/services/companion/java/com/android/server/companion/AssociationRevokeProcessor.java new file mode 100644 index 000000000000..de6382e316df --- /dev/null +++ b/services/companion/java/com/android/server/companion/AssociationRevokeProcessor.java @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.companion; + +import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; +import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION; + +import static com.android.internal.util.CollectionUtils.any; +import static com.android.server.companion.MetricUtils.logRemoveAssociation; +import static com.android.server.companion.RolesUtils.removeRoleHolderForAssociation; +import static com.android.server.companion.CompanionDeviceManagerService.PerUserAssociationSet; + +import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.annotation.UserIdInt; +import android.app.ActivityManager; +import android.companion.AssociationInfo; +import android.content.Context; +import android.content.pm.PackageManagerInternal; +import android.os.Binder; +import android.os.UserHandle; +import android.util.ArraySet; +import android.util.Log; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.companion.datatransfer.SystemDataTransferRequestStore; +import com.android.server.companion.presence.CompanionDevicePresenceMonitor; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * A class response for Association removal. + */ +@SuppressLint("LongLogTag") +public class AssociationRevokeProcessor { + + private static final String TAG = "CDM_AssociationRevokeProcessor"; + private static final boolean DEBUG = false; + private final @NonNull Context mContext; + private final @NonNull CompanionDeviceManagerService mService; + private final @NonNull AssociationStoreImpl mAssociationStore; + private final @NonNull PackageManagerInternal mPackageManagerInternal; + private final @NonNull CompanionDevicePresenceMonitor mDevicePresenceMonitor; + private final @NonNull SystemDataTransferRequestStore mSystemDataTransferRequestStore; + private final @NonNull CompanionApplicationController mCompanionAppController; + private final OnPackageVisibilityChangeListener mOnPackageVisibilityChangeListener; + private final ActivityManager mActivityManager; + + /** + * A structure that consists of a set of revoked associations that pending for role holder + * removal per each user. + * + * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo) + * @see #addToPendingRoleHolderRemoval(AssociationInfo) + * @see #removeFromPendingRoleHolderRemoval(AssociationInfo) + * @see #getPendingRoleHolderRemovalAssociationsForUser(int) + */ + @GuardedBy("mRevokedAssociationsPendingRoleHolderRemoval") + private final PerUserAssociationSet mRevokedAssociationsPendingRoleHolderRemoval = + new PerUserAssociationSet(); + /** + * Contains uid-s of packages pending to be removed from the role holder list (after + * revocation of an association), which will happen one the package is no longer visible to the + * user. + * For quicker uid -> (userId, packageName) look-up this is not a {@code Set<Integer>} but + * a {@code Map<Integer, String>} which maps uid-s to packageName-s (userId-s can be derived + * from uid-s using {@link UserHandle#getUserId(int)}). + * + * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo) + * @see #addToPendingRoleHolderRemoval(AssociationInfo) + * @see #removeFromPendingRoleHolderRemoval(AssociationInfo) + */ + @GuardedBy("mRevokedAssociationsPendingRoleHolderRemoval") + private final Map<Integer, String> mUidsPendingRoleHolderRemoval = new HashMap<>(); + + AssociationRevokeProcessor(@NonNull CompanionDeviceManagerService service, + @NonNull AssociationStoreImpl associationStore, + @NonNull PackageManagerInternal packageManager, + @NonNull CompanionDevicePresenceMonitor devicePresenceMonitor, + @NonNull CompanionApplicationController applicationController, + @NonNull SystemDataTransferRequestStore systemDataTransferRequestStore) { + mService = service; + mContext = service.getContext(); + mActivityManager = mContext.getSystemService(ActivityManager.class); + mAssociationStore = associationStore; + mPackageManagerInternal = packageManager; + mOnPackageVisibilityChangeListener = + new OnPackageVisibilityChangeListener(mActivityManager); + mDevicePresenceMonitor = devicePresenceMonitor; + mCompanionAppController = applicationController; + mSystemDataTransferRequestStore = systemDataTransferRequestStore; + } + + // TODO: also revoke notification access + void disassociateInternal(int associationId) { + final AssociationInfo association = mAssociationStore.getAssociationById(associationId); + final int userId = association.getUserId(); + final String packageName = association.getPackageName(); + final String deviceProfile = association.getDeviceProfile(); + + if (!maybeRemoveRoleHolderForAssociation(association)) { + // Need to remove the app from list of the role holders, but will have to do it later + // (the app is in foreground at the moment). + addToPendingRoleHolderRemoval(association); + } + + // Need to check if device still present now because CompanionDevicePresenceMonitor will + // remove current connected device after mAssociationStore.removeAssociation + final boolean wasPresent = mDevicePresenceMonitor.isDevicePresent(associationId); + + // Removing the association. + mAssociationStore.removeAssociation(associationId); + // Do not need to persistUserState since CompanionDeviceManagerService will get callback + // from #onAssociationChanged, and it will handle the persistUserState which including + // active and revoked association. + logRemoveAssociation(deviceProfile); + + // Remove all the system data transfer requests for the association. + mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, associationId); + + if (!wasPresent || !association.isNotifyOnDeviceNearby()) return; + // The device was connected and the app was notified: check if we need to unbind the app + // now. + final boolean shouldStayBound = any( + mAssociationStore.getAssociationsForPackage(userId, packageName), + it -> it.isNotifyOnDeviceNearby() + && mDevicePresenceMonitor.isDevicePresent(it.getId())); + if (shouldStayBound) return; + mCompanionAppController.unbindCompanionApplication(userId, packageName); + } + + /** + * First, checks if the companion application should be removed from the list role holders when + * upon association's removal, i.e.: association's profile (matches the role) is not null, + * the application does not have other associations with the same profile, etc. + * + * <p> + * Then, if establishes that the application indeed has to be removed from the list of the role + * holders, checks if it could be done right now - + * {@link android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, UserHandle, java.util.concurrent.Executor, java.util.function.Consumer) RoleManager#removeRoleHolderAsUser()} + * will kill the application's process, which leads poor user experience if the application was + * in foreground when this happened, to avoid this CDMS delays invoking + * {@code RoleManager.removeRoleHolderAsUser()} until the app is no longer in foreground. + * + * @return {@code true} if the application does NOT need be removed from the list of the role + * holders OR if the application was successfully removed from the list of role holders. + * I.e.: from the role-management perspective the association is done with. + * {@code false} if the application needs to be removed from the list of role the role + * holders, BUT it CDMS would prefer to do it later. + * I.e.: application is in the foreground at the moment, but invoking + * {@code RoleManager.removeRoleHolderAsUser()} will kill the application's process, + * which would lead to the poor UX, hence need to try later. + */ + boolean maybeRemoveRoleHolderForAssociation(@NonNull AssociationInfo association) { + if (DEBUG) Log.d(TAG, "maybeRemoveRoleHolderForAssociation() association=" + association); + final String deviceProfile = association.getDeviceProfile(); + + if (deviceProfile == null) { + // No role was granted to for this association, there is nothing else we need to here. + return true; + } + // Do not need to remove the system role since it was pre-granted by the system. + if (deviceProfile.equals(DEVICE_PROFILE_AUTOMOTIVE_PROJECTION)) { + return true; + } + + // Check if the applications is associated with another devices with the profile. If so, + // it should remain the role holder. + final int id = association.getId(); + final int userId = association.getUserId(); + final String packageName = association.getPackageName(); + final boolean roleStillInUse = any( + mAssociationStore.getAssociationsForPackage(userId, packageName), + it -> deviceProfile.equals(it.getDeviceProfile()) && id != it.getId()); + if (roleStillInUse) { + // Application should remain a role holder, there is nothing else we need to here. + return true; + } + + final int packageProcessImportance = getPackageProcessImportance(userId, packageName); + if (packageProcessImportance <= IMPORTANCE_VISIBLE) { + // Need to remove the app from the list of role holders, but the process is visible to + // the user at the moment, so we'll need to it later: log and return false. + Slog.i(TAG, "Cannot remove role holder for the removed association id=" + id + + " now - process is visible."); + return false; + } + + removeRoleHolderForAssociation(mContext, association); + return true; + } + + @SuppressLint("MissingPermission") + private int getPackageProcessImportance(@UserIdInt int userId, @NonNull String packageName) { + return Binder.withCleanCallingIdentity(() -> { + final int uid = + mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId); + return mActivityManager.getUidImportance(uid); + }); + } + + /** + * Set revoked flag for active association and add the revoked association and the uid into + * the caches. + * + * @see #mRevokedAssociationsPendingRoleHolderRemoval + * @see #mUidsPendingRoleHolderRemoval + * @see OnPackageVisibilityChangeListener + */ + void addToPendingRoleHolderRemoval(@NonNull AssociationInfo association) { + // First: set revoked flag + association = (new AssociationInfo.Builder(association)).setRevoked(true).build(); + final String packageName = association.getPackageName(); + final int userId = association.getUserId(); + final int uid = mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId); + // Second: add to the set. + synchronized (mRevokedAssociationsPendingRoleHolderRemoval) { + mRevokedAssociationsPendingRoleHolderRemoval.forUser(association.getUserId()) + .add(association); + if (!mUidsPendingRoleHolderRemoval.containsKey(uid)) { + mUidsPendingRoleHolderRemoval.put(uid, packageName); + + if (mUidsPendingRoleHolderRemoval.size() == 1) { + // Just added first uid: start the listener + mOnPackageVisibilityChangeListener.startListening(); + } + } + } + } + + /** + * Remove the revoked association from the cache and also remove the uid from the map if + * there are other associations with the same package still pending for role holder removal. + * + * @see #mRevokedAssociationsPendingRoleHolderRemoval + * @see #mUidsPendingRoleHolderRemoval + * @see OnPackageVisibilityChangeListener + */ + private void removeFromPendingRoleHolderRemoval(@NonNull AssociationInfo association) { + final String packageName = association.getPackageName(); + final int userId = association.getUserId(); + final int uid = mPackageManagerInternal.getPackageUid(packageName, /* flags */ 0, userId); + + synchronized (mRevokedAssociationsPendingRoleHolderRemoval) { + mRevokedAssociationsPendingRoleHolderRemoval.forUser(userId) + .remove(association); + + final boolean shouldKeepUidForRemoval = any( + getPendingRoleHolderRemovalAssociationsForUser(userId), + ai -> packageName.equals(ai.getPackageName())); + // Do not remove the uid from the map since other associations with + // the same packageName still pending for role holder removal. + if (!shouldKeepUidForRemoval) { + mUidsPendingRoleHolderRemoval.remove(uid); + } + + if (mUidsPendingRoleHolderRemoval.isEmpty()) { + // The set is empty now - can "turn off" the listener. + mOnPackageVisibilityChangeListener.stopListening(); + } + } + } + + /** + * @return a copy of the revoked associations set (safeguarding against + * {@code ConcurrentModificationException}-s). + */ + @NonNull Set<AssociationInfo> getPendingRoleHolderRemovalAssociationsForUser( + @UserIdInt int userId) { + synchronized (mRevokedAssociationsPendingRoleHolderRemoval) { + // Return a copy. + return new ArraySet<>(mRevokedAssociationsPendingRoleHolderRemoval.forUser(userId)); + } + } + + private String getPackageNameByUid(int uid) { + synchronized (mRevokedAssociationsPendingRoleHolderRemoval) { + return mUidsPendingRoleHolderRemoval.get(uid); + } + } + + /** + * An OnUidImportanceListener class which watches the importance of the packages. + * In this class, we ONLY interested in the importance of the running process is greater than + * {@link ActivityManager.RunningAppProcessInfo#IMPORTANCE_VISIBLE} for the uids have been added + * into the {@link #mUidsPendingRoleHolderRemoval}. Lastly remove the role holder for the + * revoked associations for the same packages. + * + * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo) + * @see #removeFromPendingRoleHolderRemoval(AssociationInfo) + * @see #getPendingRoleHolderRemovalAssociationsForUser(int) + */ + private class OnPackageVisibilityChangeListener implements + ActivityManager.OnUidImportanceListener { + final @NonNull ActivityManager mAm; + + OnPackageVisibilityChangeListener(@NonNull ActivityManager am) { + this.mAm = am; + } + + @SuppressLint("MissingPermission") + void startListening() { + Binder.withCleanCallingIdentity( + () -> mAm.addOnUidImportanceListener( + /* listener */ OnPackageVisibilityChangeListener.this, + ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE)); + } + + @SuppressLint("MissingPermission") + void stopListening() { + Binder.withCleanCallingIdentity( + () -> mAm.removeOnUidImportanceListener( + /* listener */ OnPackageVisibilityChangeListener.this)); + } + + @Override + public void onUidImportance(int uid, int importance) { + if (importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) { + // The lower the importance value the more "important" the process is. + // We are only interested when the process ceases to be visible. + return; + } + + final String packageName = getPackageNameByUid(uid); + if (packageName == null) { + // Not interested in this uid. + return; + } + + final int userId = UserHandle.getUserId(uid); + + boolean needToPersistStateForUser = false; + + for (AssociationInfo association : + getPendingRoleHolderRemovalAssociationsForUser(userId)) { + if (!packageName.equals(association.getPackageName())) continue; + + if (!maybeRemoveRoleHolderForAssociation(association)) { + // Did not remove the role holder, will have to try again later. + continue; + } + + removeFromPendingRoleHolderRemoval(association); + needToPersistStateForUser = true; + } + + if (needToPersistStateForUser) { + mService.postPersistUserState(userId); + } + } + } +} diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java index ba1f51baa624..09c77939eb7b 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java @@ -22,7 +22,6 @@ import static android.Manifest.permission.DELIVER_COMPANION_MESSAGES; import static android.Manifest.permission.MANAGE_COMPANION_DEVICES; import static android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE; import static android.Manifest.permission.USE_COMPANION_TRANSPORTS; -import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION; import static android.companion.DevicePresenceEvent.EVENT_BLE_APPEARED; import static android.companion.DevicePresenceEvent.EVENT_BLE_DISAPPEARED; @@ -39,7 +38,6 @@ import static com.android.internal.util.CollectionUtils.any; import static com.android.internal.util.Preconditions.checkState; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.companion.AssociationStore.CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED; -import static com.android.server.companion.MetricUtils.logRemoveAssociation; import static com.android.server.companion.PackageUtils.isRestrictedSettingsAllowed; import static com.android.server.companion.PackageUtils.enforceUsesCompanionDeviceFeature; import static com.android.server.companion.PackageUtils.getPackageInfo; @@ -49,7 +47,6 @@ import static com.android.server.companion.PermissionsUtils.enforceCallerCanObse import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOr; import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOrCanInteractWithUserId; import static com.android.server.companion.PermissionsUtils.sanitizeWithCallerChecks; -import static com.android.server.companion.RolesUtils.removeRoleHolderForAssociation; import static java.util.Objects.requireNonNull; import static java.util.concurrent.TimeUnit.DAYS; @@ -61,7 +58,6 @@ import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.UserIdInt; import android.app.ActivityManager; -import android.app.ActivityManager.RunningAppProcessInfo; import android.app.ActivityManagerInternal; import android.app.AppOpsManager; import android.app.NotificationManager; @@ -149,7 +145,7 @@ public class CompanionDeviceManagerService extends SystemService { static final String TAG = "CDM_CompanionDeviceManagerService"; static final boolean DEBUG = false; - /** Range of Association IDs allocated for a user.*/ + /** Range of Association IDs allocated for a user. */ private static final int ASSOCIATIONS_IDS_PER_USER_RANGE = 100000; private static final long PAIR_WITHOUT_PROMPT_WINDOW_MS = 10 * 60 * 1000; // 10 min @@ -162,8 +158,6 @@ public class CompanionDeviceManagerService extends SystemService { private static final int MAX_CN_LENGTH = 500; private final ActivityManager mActivityManager; - private final OnPackageVisibilityChangeListener mOnPackageVisibilityChangeListener; - private PersistentDataStore mPersistentStore; private final PersistUserStateHandler mUserPersistenceHandler; @@ -175,6 +169,7 @@ public class CompanionDeviceManagerService extends SystemService { private CompanionDevicePresenceMonitor mDevicePresenceMonitor; private CompanionApplicationController mCompanionAppController; private CompanionTransportManager mTransportManager; + private AssociationRevokeProcessor mAssociationRevokeProcessor; private final ActivityTaskManagerInternal mAtmInternal; private final ActivityManagerInternal mAmInternal; @@ -193,33 +188,6 @@ public class CompanionDeviceManagerService extends SystemService { @GuardedBy("mPreviouslyUsedIds") private final SparseArray<Map<String, Set<Integer>>> mPreviouslyUsedIds = new SparseArray<>(); - /** - * A structure that consists of a set of revoked associations that pending for role holder - * removal per each user. - * - * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo) - * @see #addToPendingRoleHolderRemoval(AssociationInfo) - * @see #removeFromPendingRoleHolderRemoval(AssociationInfo) - * @see #getPendingRoleHolderRemovalAssociationsForUser(int) - */ - @GuardedBy("mRevokedAssociationsPendingRoleHolderRemoval") - private final PerUserAssociationSet mRevokedAssociationsPendingRoleHolderRemoval = - new PerUserAssociationSet(); - /** - * Contains uid-s of packages pending to be removed from the role holder list (after - * revocation of an association), which will happen one the package is no longer visible to the - * user. - * For quicker uid -> (userId, packageName) look-up this is not a {@code Set<Integer>} but - * a {@code Map<Integer, String>} which maps uid-s to packageName-s (userId-s can be derived - * from uid-s using {@link UserHandle#getUserId(int)}). - * - * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo) - * @see #addToPendingRoleHolderRemoval(AssociationInfo) - * @see #removeFromPendingRoleHolderRemoval(AssociationInfo) - */ - @GuardedBy("mRevokedAssociationsPendingRoleHolderRemoval") - private final Map<Integer, String> mUidsPendingRoleHolderRemoval = new HashMap<>(); - private final RemoteCallbackList<IOnAssociationsChangedListener> mListeners = new RemoteCallbackList<>(); @@ -243,8 +211,6 @@ public class CompanionDeviceManagerService extends SystemService { mAssociationStore = new AssociationStoreImpl(); mSystemDataTransferRequestStore = new SystemDataTransferRequestStore(); - mOnPackageVisibilityChangeListener = - new OnPackageVisibilityChangeListener(mActivityManager); mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); mObservableUuidStore = new ObservableUuidStore(); } @@ -276,6 +242,9 @@ public class CompanionDeviceManagerService extends SystemService { mSystemDataTransferProcessor = new SystemDataTransferProcessor(this, mPackageManagerInternal, mAssociationStore, mSystemDataTransferRequestStore, mTransportManager); + mAssociationRevokeProcessor = new AssociationRevokeProcessor(this, mAssociationStore, + mPackageManagerInternal, mDevicePresenceMonitor, mCompanionAppController, + mSystemDataTransferRequestStore); // TODO(b/279663946): move context sync to a dedicated system service mCrossDeviceSyncController = new CrossDeviceSyncController(getContext(), mTransportManager); @@ -307,12 +276,13 @@ public class CompanionDeviceManagerService extends SystemService { mBackupRestoreProcessor.addToPendingAppInstall(association); } else if (!association.isRevoked()) { activeAssociations.add(association); - } else if (maybeRemoveRoleHolderForAssociation(association)) { + } else if (mAssociationRevokeProcessor.maybeRemoveRoleHolderForAssociation( + association)) { // Nothing more to do here, but we'll need to persist all the associations to the // disk afterwards. usersToPersistStateFor.add(association.getUserId()); } else { - addToPendingRoleHolderRemoval(association); + mAssociationRevokeProcessor.addToPendingRoleHolderRemoval(association); } } @@ -374,7 +344,7 @@ public class CompanionDeviceManagerService extends SystemService { final List<ParcelUuid> deviceUuids = ArrayUtils.isEmpty(bluetoothDeviceUuids) ? Collections.emptyList() : Arrays.asList(bluetoothDeviceUuids); - for (AssociationInfo ai: + for (AssociationInfo ai : mAssociationStore.getAssociationsByAddress(bluetoothDevice.getAddress())) { Slog.i(TAG, "onUserUnlocked, device id( " + ai.getId() + " ) is connected"); mDevicePresenceMonitor.onBluetoothCompanionDeviceConnected(ai.getId()); @@ -495,7 +465,7 @@ public class CompanionDeviceManagerService extends SystemService { final String packageName = uuid.getPackageName(); final int userId = uuid.getUserId(); - switch(event) { + switch (event) { case EVENT_BT_CONNECTED: if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) { mCompanionAppController.bindCompanionApplication( @@ -544,8 +514,8 @@ public class CompanionDeviceManagerService extends SystemService { /** * @return whether the package should be bound (i.e. at least one of the devices associated with - * the package is currently present OR the UUID to be observed by this package is - * currently present). + * the package is currently present OR the UUID to be observed by this package is + * currently present). */ private boolean shouldBindPackage(@UserIdInt int userId, @NonNull String packageName) { final List<AssociationInfo> packageAssociations = @@ -599,7 +569,8 @@ public class CompanionDeviceManagerService extends SystemService { allAssociations = new ArrayList<>( mAssociationStore.getAssociationsForUser(userId)); // ... and add the revoked (removed) association, that are yet to be permanently removed. - allAssociations.addAll(getPendingRoleHolderRemovalAssociationsForUser(userId)); + allAssociations.addAll( + mAssociationRevokeProcessor.getPendingRoleHolderRemovalAssociationsForUser(userId)); // ... and add the restored associations that are pending missing package installation. allAssociations.addAll(mBackupRestoreProcessor .getAssociationsPendingAppInstallForUser(userId)); @@ -654,7 +625,7 @@ public class CompanionDeviceManagerService extends SystemService { } // Clear role holders for (AssociationInfo association : associationsForPackage) { - maybeRemoveRoleHolderForAssociation(association); + mAssociationRevokeProcessor.maybeRemoveRoleHolderForAssociation(association); } // Clear the uuids to be observed. for (ObservableUuid uuid : uuidsTobeObserved) { @@ -712,7 +683,7 @@ public class CompanionDeviceManagerService extends SystemService { final int id = association.getId(); Slog.i(TAG, "Removing inactive self-managed association id=" + id); - disassociateInternal(id); + mAssociationRevokeProcessor.disassociateInternal(id); } } @@ -857,7 +828,7 @@ public class CompanionDeviceManagerService extends SystemService { final AssociationInfo association = getAssociationWithCallerChecks(userId, packageName, deviceMacAddress); - disassociateInternal(association.getId()); + mAssociationRevokeProcessor.disassociateInternal(association.getId()); } @Override @@ -866,7 +837,7 @@ public class CompanionDeviceManagerService extends SystemService { final AssociationInfo association = getAssociationWithCallerChecks(associationId); - disassociateInternal(association.getId()); + mAssociationRevokeProcessor.disassociateInternal(association.getId()); } @Override @@ -902,9 +873,9 @@ public class CompanionDeviceManagerService extends SystemService { } /** - * @deprecated Use - * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)} instead. - */ + * @deprecated Use + * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)} instead. + */ @Deprecated @Override public boolean hasNotificationAccess(ComponentName component) throws RemoteException { @@ -1300,7 +1271,7 @@ public class CompanionDeviceManagerService extends SystemService { return new CompanionDeviceShellCommand(CompanionDeviceManagerService.this, mAssociationStore, mDevicePresenceMonitor, mTransportManager, mSystemDataTransferProcessor, mAssociationRequestsProcessor, - mBackupRestoreProcessor) + mBackupRestoreProcessor, mAssociationRevokeProcessor) .exec(this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), args); } @@ -1381,7 +1352,7 @@ public class CompanionDeviceManagerService extends SystemService { // another association by the time when it is activated from the package installation. final Set<AssociationInfo> pendingAssociations = mBackupRestoreProcessor .getAssociationsPendingAppInstallForUser(userId); - for (AssociationInfo it: pendingAssociations) { + for (AssociationInfo it : pendingAssociations) { usedIds.put(it.getId(), true); } @@ -1407,198 +1378,6 @@ public class CompanionDeviceManagerService extends SystemService { } } - // TODO: also revoke notification access - void disassociateInternal(int associationId) { - final AssociationInfo association = mAssociationStore.getAssociationById(associationId); - final int userId = association.getUserId(); - final String packageName = association.getPackageName(); - final String deviceProfile = association.getDeviceProfile(); - - if (!maybeRemoveRoleHolderForAssociation(association)) { - // Need to remove the app from list of the role holders, but will have to do it later - // (the app is in foreground at the moment). - addToPendingRoleHolderRemoval(association); - } - - // Need to check if device still present now because CompanionDevicePresenceMonitor will - // remove current connected device after mAssociationStore.removeAssociation - final boolean wasPresent = mDevicePresenceMonitor.isDevicePresent(associationId); - - // Removing the association. - mAssociationStore.removeAssociation(associationId); - // Do not need to persistUserState since CompanionDeviceManagerService will get callback - // from #onAssociationChanged, and it will handle the persistUserState which including - // active and revoked association. - logRemoveAssociation(deviceProfile); - - // Remove all the system data transfer requests for the association. - mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, associationId); - - if (!wasPresent || !association.isNotifyOnDeviceNearby()) return; - // The device was connected and the app was notified: check if we need to unbind the app - // now. - final boolean shouldStayBound = any( - mAssociationStore.getAssociationsForPackage(userId, packageName), - it -> it.isNotifyOnDeviceNearby() - && mDevicePresenceMonitor.isDevicePresent(it.getId())); - if (shouldStayBound) return; - mCompanionAppController.unbindCompanionApplication(userId, packageName); - } - - /** - * First, checks if the companion application should be removed from the list role holders when - * upon association's removal, i.e.: association's profile (matches the role) is not null, - * the application does not have other associations with the same profile, etc. - * - * <p> - * Then, if establishes that the application indeed has to be removed from the list of the role - * holders, checks if it could be done right now - - * {@link android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, UserHandle, java.util.concurrent.Executor, java.util.function.Consumer) RoleManager#removeRoleHolderAsUser()} - * will kill the application's process, which leads poor user experience if the application was - * in foreground when this happened, to avoid this CDMS delays invoking - * {@code RoleManager.removeRoleHolderAsUser()} until the app is no longer in foreground. - * - * @return {@code true} if the application does NOT need be removed from the list of the role - * holders OR if the application was successfully removed from the list of role holders. - * I.e.: from the role-management perspective the association is done with. - * {@code false} if the application needs to be removed from the list of role the role - * holders, BUT it CDMS would prefer to do it later. - * I.e.: application is in the foreground at the moment, but invoking - * {@code RoleManager.removeRoleHolderAsUser()} will kill the application's process, - * which would lead to the poor UX, hence need to try later. - */ - - private boolean maybeRemoveRoleHolderForAssociation(@NonNull AssociationInfo association) { - if (DEBUG) Log.d(TAG, "maybeRemoveRoleHolderForAssociation() association=" + association); - - final String deviceProfile = association.getDeviceProfile(); - if (deviceProfile == null) { - // No role was granted to for this association, there is nothing else we need to here. - return true; - } - // Do not need to remove the system role since it was pre-granted by the system. - if (deviceProfile.equals(DEVICE_PROFILE_AUTOMOTIVE_PROJECTION)) { - return true; - } - - // Check if the applications is associated with another devices with the profile. If so, - // it should remain the role holder. - final int id = association.getId(); - final int userId = association.getUserId(); - final String packageName = association.getPackageName(); - final boolean roleStillInUse = any( - mAssociationStore.getAssociationsForPackage(userId, packageName), - it -> deviceProfile.equals(it.getDeviceProfile()) && id != it.getId()); - if (roleStillInUse) { - // Application should remain a role holder, there is nothing else we need to here. - return true; - } - - final int packageProcessImportance = getPackageProcessImportance(userId, packageName); - if (packageProcessImportance <= IMPORTANCE_VISIBLE) { - // Need to remove the app from the list of role holders, but the process is visible to - // the user at the moment, so we'll need to it later: log and return false. - Slog.i(TAG, "Cannot remove role holder for the removed association id=" + id - + " now - process is visible."); - return false; - } - - removeRoleHolderForAssociation(getContext(), association); - return true; - } - - private int getPackageProcessImportance(@UserIdInt int userId, @NonNull String packageName) { - return Binder.withCleanCallingIdentity(() -> { - final int uid = - mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId); - return mActivityManager.getUidImportance(uid); - }); - } - - /** - * Set revoked flag for active association and add the revoked association and the uid into - * the caches. - * - * @see #mRevokedAssociationsPendingRoleHolderRemoval - * @see #mUidsPendingRoleHolderRemoval - * @see OnPackageVisibilityChangeListener - */ - private void addToPendingRoleHolderRemoval(@NonNull AssociationInfo association) { - // First: set revoked flag. - association = (new AssociationInfo.Builder(association)) - .setRevoked(true) - .build(); - - final String packageName = association.getPackageName(); - final int userId = association.getUserId(); - final int uid = mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId); - - // Second: add to the set. - synchronized (mRevokedAssociationsPendingRoleHolderRemoval) { - mRevokedAssociationsPendingRoleHolderRemoval.forUser(association.getUserId()) - .add(association); - if (!mUidsPendingRoleHolderRemoval.containsKey(uid)) { - mUidsPendingRoleHolderRemoval.put(uid, packageName); - - if (mUidsPendingRoleHolderRemoval.size() == 1) { - // Just added first uid: start the listener - mOnPackageVisibilityChangeListener.startListening(); - } - } - } - } - - /** - * Remove the revoked association from the cache and also remove the uid from the map if - * there are other associations with the same package still pending for role holder removal. - * - * @see #mRevokedAssociationsPendingRoleHolderRemoval - * @see #mUidsPendingRoleHolderRemoval - * @see OnPackageVisibilityChangeListener - */ - private void removeFromPendingRoleHolderRemoval(@NonNull AssociationInfo association) { - final String packageName = association.getPackageName(); - final int userId = association.getUserId(); - final int uid = mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId); - - synchronized (mRevokedAssociationsPendingRoleHolderRemoval) { - mRevokedAssociationsPendingRoleHolderRemoval.forUser(userId) - .remove(association); - - final boolean shouldKeepUidForRemoval = any( - getPendingRoleHolderRemovalAssociationsForUser(userId), - ai -> packageName.equals(ai.getPackageName())); - // Do not remove the uid from the map since other associations with - // the same packageName still pending for role holder removal. - if (!shouldKeepUidForRemoval) { - mUidsPendingRoleHolderRemoval.remove(uid); - } - - if (mUidsPendingRoleHolderRemoval.isEmpty()) { - // The set is empty now - can "turn off" the listener. - mOnPackageVisibilityChangeListener.stopListening(); - } - } - } - - /** - * @return a copy of the revoked associations set (safeguarding against - * {@code ConcurrentModificationException}-s). - */ - private @NonNull Set<AssociationInfo> getPendingRoleHolderRemovalAssociationsForUser( - @UserIdInt int userId) { - synchronized (mRevokedAssociationsPendingRoleHolderRemoval) { - // Return a copy. - return new ArraySet<>(mRevokedAssociationsPendingRoleHolderRemoval.forUser(userId)); - } - } - - private String getPackageNameByUid(int uid) { - synchronized (mRevokedAssociationsPendingRoleHolderRemoval) { - return mUidsPendingRoleHolderRemoval.get(uid); - } - } - void updateSpecialAccessPermissionForAssociatedPackage(AssociationInfo association) { final PackageInfo packageInfo = getPackageInfo(getContext(), association.getUserId(), association.getPackageName()); @@ -1704,11 +1483,11 @@ public class CompanionDeviceManagerService extends SystemService { private final AssociationStore.OnChangeListener mAssociationStoreChangeListener = new AssociationStore.OnChangeListener() { - @Override - public void onAssociationChanged(int changeType, AssociationInfo association) { - onAssociationChangedInternal(changeType, association); - } - }; + @Override + public void onAssociationChanged(int changeType, AssociationInfo association) { + onAssociationChangedInternal(changeType, association); + } + }; private final CompanionDevicePresenceMonitor.Callback mDevicePresenceCallback = new CompanionDevicePresenceMonitor.Callback() { @@ -1731,7 +1510,7 @@ public class CompanionDeviceManagerService extends SystemService { public void onDevicePresenceEventByUuid(ObservableUuid uuid, int event) { onDevicePresenceEventByUuidInternal(uuid, event); } - }; + }; private final PackageMonitor mPackageMonitor = new PackageMonitor() { @Override @@ -1887,73 +1666,8 @@ public class CompanionDeviceManagerService extends SystemService { } } - /** - * An OnUidImportanceListener class which watches the importance of the packages. - * In this class, we ONLY interested in the importance of the running process is greater than - * {@link RunningAppProcessInfo.IMPORTANCE_VISIBLE} for the uids have been added into the - * {@link mUidsPendingRoleHolderRemoval}. Lastly remove the role holder for the revoked - * associations for the same packages. - * - * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo) - * @see #removeFromPendingRoleHolderRemoval(AssociationInfo) - * @see #getPendingRoleHolderRemovalAssociationsForUser(int) - */ - private class OnPackageVisibilityChangeListener implements - ActivityManager.OnUidImportanceListener { - final @NonNull ActivityManager mAm; - - OnPackageVisibilityChangeListener(@NonNull ActivityManager am) { - this.mAm = am; - } - - void startListening() { - Binder.withCleanCallingIdentity( - () -> mAm.addOnUidImportanceListener( - /* listener */ OnPackageVisibilityChangeListener.this, - RunningAppProcessInfo.IMPORTANCE_VISIBLE)); - } - - void stopListening() { - Binder.withCleanCallingIdentity( - () -> mAm.removeOnUidImportanceListener( - /* listener */ OnPackageVisibilityChangeListener.this)); - } - - @Override - public void onUidImportance(int uid, int importance) { - if (importance <= RunningAppProcessInfo.IMPORTANCE_VISIBLE) { - // The lower the importance value the more "important" the process is. - // We are only interested when the process ceases to be visible. - return; - } - - final String packageName = getPackageNameByUid(uid); - if (packageName == null) { - // Not interested in this uid. - return; - } - - final int userId = UserHandle.getUserId(uid); - - boolean needToPersistStateForUser = false; - - for (AssociationInfo association : - getPendingRoleHolderRemovalAssociationsForUser(userId)) { - if (!packageName.equals(association.getPackageName())) continue; - - if (!maybeRemoveRoleHolderForAssociation(association)) { - // Did not remove the role holder, will have to try again later. - continue; - } - - removeFromPendingRoleHolderRemoval(association); - needToPersistStateForUser = true; - } - - if (needToPersistStateForUser) { - mUserPersistenceHandler.postPersistUserState(userId); - } - } + void postPersistUserState(@UserIdInt int userId) { + mUserPersistenceHandler.postPersistUserState(userId); } static class PerUserAssociationSet extends PerUser<Set<AssociationInfo>> { diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java index 5663434e2b6d..de4f2b60170f 100644 --- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java +++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java @@ -45,6 +45,7 @@ class CompanionDeviceShellCommand extends ShellCommand { private static final String TAG = "CDM_CompanionDeviceShellCommand"; private final CompanionDeviceManagerService mService; + private final AssociationRevokeProcessor mRevokeProcessor; private final AssociationStoreImpl mAssociationStore; private final CompanionDevicePresenceMonitor mDevicePresenceMonitor; private final CompanionTransportManager mTransportManager; @@ -59,7 +60,8 @@ class CompanionDeviceShellCommand extends ShellCommand { CompanionTransportManager transportManager, SystemDataTransferProcessor systemDataTransferProcessor, AssociationRequestsProcessor associationRequestsProcessor, - BackupRestoreProcessor backupRestoreProcessor) { + BackupRestoreProcessor backupRestoreProcessor, + AssociationRevokeProcessor revokeProcessor) { mService = service; mAssociationStore = associationStore; mDevicePresenceMonitor = devicePresenceMonitor; @@ -67,6 +69,7 @@ class CompanionDeviceShellCommand extends ShellCommand { mSystemDataTransferProcessor = systemDataTransferProcessor; mAssociationRequestsProcessor = associationRequestsProcessor; mBackupRestoreProcessor = backupRestoreProcessor; + mRevokeProcessor = revokeProcessor; } @Override @@ -126,7 +129,7 @@ class CompanionDeviceShellCommand extends ShellCommand { final AssociationInfo association = mService.getAssociationWithCallerChecks(userId, packageName, address); if (association != null) { - mService.disassociateInternal(association.getId()); + mRevokeProcessor.disassociateInternal(association.getId()); } } break; @@ -138,7 +141,7 @@ class CompanionDeviceShellCommand extends ShellCommand { mAssociationStore.getAssociationsForPackage(userId, packageName); for (AssociationInfo association : userAssociations) { if (sanitizeWithCallerChecks(mService.getContext(), association) != null) { - mService.disassociateInternal(association.getId()); + mRevokeProcessor.disassociateInternal(association.getId()); } } } diff --git a/services/core/Android.bp b/services/core/Android.bp index 7940ca64b330..d1d7ee7ba0e4 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -41,16 +41,18 @@ java_library_static { genrule { name: "services.core.protologsrc", srcs: [ + ":protolog-impl", ":protolog-groups", ":services.core-sources-am-wm", ], tools: ["protologtool"], cmd: "$(location protologtool) transform-protolog-calls " + "--protolog-class com.android.internal.protolog.common.ProtoLog " + - "--protolog-impl-class com.android.internal.protolog.ProtoLogImpl " + - "--protolog-cache-class 'com.android.server.wm.ProtoLogCache' " + "--loggroups-class com.android.internal.protolog.ProtoLogGroup " + "--loggroups-jar $(location :protolog-groups) " + + "--viewer-config-file-path /etc/core.protolog.pb " + + "--legacy-viewer-config-file-path /system/etc/protolog.conf.json.gz " + + "--legacy-output-file-path /data/misc/wmtrace/wm_log.winscope " + "--output-srcjar $(out) " + "$(locations :services.core-sources-am-wm)", out: ["services.core.protolog.srcjar"], @@ -67,12 +69,30 @@ genrule { "--protolog-class com.android.internal.protolog.common.ProtoLog " + "--loggroups-class com.android.internal.protolog.ProtoLogGroup " + "--loggroups-jar $(location :protolog-groups) " + - "--viewer-conf $(out) " + + "--viewer-config-type json " + + "--viewer-config $(out) " + "$(locations :services.core-sources-am-wm)", out: ["services.core.protolog.json"], } genrule { + name: "gen-core.protolog.pb", + srcs: [ + ":protolog-groups", + ":services.core-sources-am-wm", + ], + tools: ["protologtool"], + cmd: "$(location protologtool) generate-viewer-config " + + "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--loggroups-class com.android.internal.protolog.ProtoLogGroup " + + "--loggroups-jar $(location :protolog-groups) " + + "--viewer-config-type proto " + + "--viewer-config $(out) " + + "$(locations :services.core-sources-am-wm)", + out: ["core.protolog.pb"], +} + +genrule { name: "checked-protolog.json", srcs: [ ":generate-protolog.json", @@ -89,6 +109,22 @@ genrule { } genrule { + name: "checked-core.protolog.pb", + srcs: [ + ":gen-core.protolog.pb", + ":file-core.protolog.pb", + ], + cmd: "cp $(location :gen-core.protolog.pb) $(out) && " + + "{ ! (diff $(out) $(location :file-core.protolog.pb) | grep -q '^<') || " + + "{ echo -e '\\n\\n################################################################\\n#\\n" + + "# ERROR: ProtoLog viewer config is stale. To update it, run:\\n#\\n" + + "# cp $${ANDROID_BUILD_TOP}/$(location :gen-core.protolog.pb) " + + "$${ANDROID_BUILD_TOP}/$(location :file-core.protolog.pb)\\n#\\n" + + "################################################################\\n\\n' >&2 && false; } }", + out: ["core.protolog.pb"], +} + +genrule { name: "statslog-art-java-gen", tools: ["stats-log-api-gen"], cmd: "$(location stats-log-api-gen) --java $(out) --module art" + @@ -158,6 +194,7 @@ java_library_static { "default_television.xml", "gps_debug.conf", "protolog.conf.json.gz", + "core.protolog.pb", ], static_libs: [ @@ -269,3 +306,8 @@ prebuilt_etc { name: "protolog.conf.json.gz", src: ":services.core.json.gz", } + +prebuilt_etc { + name: "core.protolog.pb", + src: ":checked-core.protolog.pb", +} diff --git a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java index 0904c47b61f2..7d8aad7ab490 100644 --- a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java +++ b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java @@ -63,6 +63,9 @@ public final class SensitiveContentProtectionManagerService extends SystemServic @Nullable private MediaProjectionManager mProjectionManager; @Nullable private WindowManagerInternal mWindowManager; + // screen recorder packages exempted from screen share protection. + private ArraySet<String> mExemptedPackages = null; + final Object mSensitiveContentProtectionLock = new Object(); @GuardedBy("mSensitiveContentProtectionLock") @@ -76,7 +79,7 @@ public final class SensitiveContentProtectionManagerService extends SystemServic Trace.beginSection( "SensitiveContentProtectionManagerService.onProjectionStart"); try { - onProjectionStart(); + onProjectionStart(info); } finally { Trace.endSection(); } @@ -113,15 +116,25 @@ public final class SensitiveContentProtectionManagerService extends SystemServic if (DEBUG) Log.d(TAG, "onBootPhase - PHASE_BOOT_COMPLETED"); init(getContext().getSystemService(MediaProjectionManager.class), - LocalServices.getService(WindowManagerInternal.class)); + LocalServices.getService(WindowManagerInternal.class), + getExemptedPackages()); if (sensitiveContentAppProtection()) { publishBinderService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE, new SensitiveContentProtectionManagerServiceBinder()); } } + // These packages are exempted from screen share protection. + private ArraySet<String> getExemptedPackages() { + final ArraySet<String> exemptedPackages = + SystemConfig.getInstance().getBugreportWhitelistedPackages(); + // TODO(b/323361046) - Add sys ui recorder package. + return exemptedPackages; + } + @VisibleForTesting - void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager) { + void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager, + ArraySet<String> exemptedPackages) { if (DEBUG) Log.d(TAG, "init"); Objects.requireNonNull(projectionManager); @@ -129,6 +142,7 @@ public final class SensitiveContentProtectionManagerService extends SystemServic mProjectionManager = projectionManager; mWindowManager = windowManager; + mExemptedPackages = exemptedPackages; // TODO(b/317250444): use MediaProjectionManagerService directly, reduces unnecessary // handler, delegate, and binder death recipient @@ -165,7 +179,11 @@ public final class SensitiveContentProtectionManagerService extends SystemServic } } - private void onProjectionStart() { + private void onProjectionStart(MediaProjectionInfo info) { + if (mExemptedPackages != null && mExemptedPackages.contains(info.getPackageName())) { + Log.w(TAG, info.getPackageName() + " is exempted from screen share protection."); + return; + } // TODO(b/324447419): move GlobalSettings lookup to background thread boolean disableScreenShareProtections = Settings.Global.getInt(getContext().getContentResolver(), diff --git a/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java b/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java index 3312be231516..96fee9296215 100644 --- a/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java +++ b/services/core/java/com/android/server/adaptiveauth/AdaptiveAuthService.java @@ -32,8 +32,10 @@ import android.os.SystemClock; import android.util.Log; import android.util.Slog; import android.util.SparseIntArray; +import android.util.SparseLongArray; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockSettingsInternal; import com.android.internal.widget.LockSettingsStateListener; @@ -57,6 +59,8 @@ public class AdaptiveAuthService extends SystemService { private static final int MSG_REPORT_BIOMETRIC_AUTH_ATTEMPT = 2; private static final int AUTH_SUCCESS = 1; private static final int AUTH_FAILURE = 0; + private static final int TYPE_PRIMARY_AUTH = 0; + private static final int TYPE_BIOMETRIC_AUTH = 1; private final LockPatternUtils mLockPatternUtils; private final LockSettingsInternal mLockSettings; @@ -67,6 +71,7 @@ public class AdaptiveAuthService extends SystemService { private final UserManagerInternal mUserManager; @VisibleForTesting final SparseIntArray mFailedAttemptsForUser = new SparseIntArray(); + private final SparseLongArray mLastLockedTimestamp = new SparseLongArray(); public AdaptiveAuthService(Context context) { this(context, new LockPatternUtils(context)); @@ -170,7 +175,7 @@ public class AdaptiveAuthService extends SystemService { Slog.d(TAG, "handleReportPrimaryAuthAttempt: success=" + success + ", userId=" + userId); } - reportAuthAttempt(success, userId); + reportAuthAttempt(TYPE_PRIMARY_AUTH, success, userId); } private void handleReportBiometricAuthAttempt(boolean success, int userId) { @@ -178,13 +183,24 @@ public class AdaptiveAuthService extends SystemService { Slog.d(TAG, "handleReportBiometricAuthAttempt: success=" + success + ", userId=" + userId); } - reportAuthAttempt(success, userId); + reportAuthAttempt(TYPE_BIOMETRIC_AUTH, success, userId); } - private void reportAuthAttempt(boolean success, int userId) { + private void reportAuthAttempt(int authType, boolean success, int userId) { if (success) { // Deleting the entry effectively resets the counter of failed attempts for the user mFailedAttemptsForUser.delete(userId); + + // Collect metrics if the device was locked by adaptive auth before + if (mLastLockedTimestamp.indexOfKey(userId) >= 0) { + final long lastLockedTime = mLastLockedTimestamp.get(userId); + collectTimeElapsedSinceLastLocked( + lastLockedTime, SystemClock.elapsedRealtime(), authType); + + // Remove the entry for the last locked time because a successful auth just happened + // and metrics have been collected + mLastLockedTimestamp.delete(userId); + } return; } @@ -210,6 +226,34 @@ public class AdaptiveAuthService extends SystemService { lockDevice(userId); } + private static void collectTimeElapsedSinceLastLocked(long lastLockedTime, long authTime, + int authType) { + final int unlockType = switch (authType) { + case TYPE_PRIMARY_AUTH -> FrameworkStatsLog + .ADAPTIVE_AUTH_UNLOCK_AFTER_LOCK_REPORTED__UNLOCK_TYPE__PRIMARY_AUTH; + case TYPE_BIOMETRIC_AUTH -> FrameworkStatsLog + .ADAPTIVE_AUTH_UNLOCK_AFTER_LOCK_REPORTED__UNLOCK_TYPE__BIOMETRIC_AUTH; + default -> FrameworkStatsLog + .ADAPTIVE_AUTH_UNLOCK_AFTER_LOCK_REPORTED__UNLOCK_TYPE__UNKNOWN; + }; + + if (DEBUG) { + Slog.d(TAG, "collectTimeElapsedSinceLastLockedForUser: " + + "lastLockedTime=" + lastLockedTime + + ", authTime=" + authTime + + ", unlockType=" + unlockType); + } + + // This usually shouldn't happen, and just check out of an abundance of caution + if (lastLockedTime > authTime) { + return; + } + + // Log to statsd + FrameworkStatsLog.write(FrameworkStatsLog.ADAPTIVE_AUTH_UNLOCK_AFTER_LOCK_REPORTED, + lastLockedTime, authTime, unlockType); + } + /** * Locks the device and requires primary auth or biometric auth for unlocking */ @@ -234,5 +278,9 @@ public class AdaptiveAuthService extends SystemService { // Lock the device mWindowManager.lockNow(); + + // Record the time that the device is locked by adaptive auth to collect metrics when the + // next successful primary or biometric auth happens + mLastLockedTimestamp.put(userId, SystemClock.elapsedRealtime()); } } diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index b8f6b3f3a988..b8e09cce93b9 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -4133,7 +4133,7 @@ public final class ActiveServices { || (callerApp.mState.getCurProcState() <= PROCESS_STATE_TOP && c.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)), b.client); - if ((serviceBindingOomAdjPolicy + if (!s.mOomAdjBumpedInExec && (serviceBindingOomAdjPolicy & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT) == 0) { needOomAdj = true; mAm.enqueueOomAdjTargetLocked(s.app); @@ -4277,7 +4277,7 @@ public final class ActiveServices { } serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false, false, - !Flags.serviceBindingOomAdjPolicy() || b == null || !b.mSkippedOomAdj + !Flags.serviceBindingOomAdjPolicy() || r.mOomAdjBumpedInExec ? OOM_ADJ_REASON_EXECUTING_SERVICE : OOM_ADJ_REASON_NONE); } } finally { @@ -4398,7 +4398,6 @@ public final class ActiveServices { + (b != null ? b.apps.size() : 0)); boolean inDestroying = mDestroyingServices.contains(r); - boolean skipOomAdj = false; if (b != null) { if (b.apps.size() > 0 && !inDestroying) { // Applications have already bound since the last @@ -4423,11 +4422,11 @@ public final class ActiveServices { // a new client. b.doRebind = true; } - skipOomAdj = Flags.serviceBindingOomAdjPolicy() && b.mSkippedOomAdj; } serviceDoneExecutingLocked(r, inDestroying, false, false, - skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE); + !Flags.serviceBindingOomAdjPolicy() || r.mOomAdjBumpedInExec + ? OOM_ADJ_REASON_UNBIND_SERVICE : OOM_ADJ_REASON_NONE); } } finally { mAm.mInjector.restoreCallingIdentity(origId); @@ -4905,9 +4904,8 @@ public final class ActiveServices { * Bump the given service record into executing state. * @param oomAdjReason The caller requests it to perform the oomAdjUpdate not {@link * ActivityManagerInternal#OOM_ADJ_REASON_NONE}. - * @return {@code true} if it performed oomAdjUpdate. */ - private boolean bumpServiceExecutingLocked( + private void bumpServiceExecutingLocked( ServiceRecord r, boolean fg, String why, @OomAdjReason int oomAdjReason, boolean skipTimeoutIfPossible) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING " @@ -4972,19 +4970,17 @@ public final class ActiveServices { } } } - boolean oomAdjusted = false; if (oomAdjReason != OOM_ADJ_REASON_NONE && r.app != null && r.app.mState.getCurProcState() > ActivityManager.PROCESS_STATE_SERVICE) { // Force an immediate oomAdjUpdate, so the client app could be in the correct process // state before doing any service related transactions mAm.enqueueOomAdjTargetLocked(r.app); mAm.updateOomAdjPendingTargetsLocked(oomAdjReason); - oomAdjusted = true; + r.mOomAdjBumpedInExec = true; } r.executeFg |= fg; r.executeNesting++; r.executingStart = SystemClock.uptimeMillis(); - return oomAdjusted; } private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, @@ -5001,7 +4997,7 @@ public final class ActiveServices { & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_BIND) != 0; if ((!i.requested || rebind) && i.apps.size() > 0) { try { - i.mSkippedOomAdj = !bumpServiceExecutingLocked(r, execInFg, "bind", + bumpServiceExecutingLocked(r, execInFg, "bind", skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_BIND_SERVICE, skipOomAdj /* skipTimeoutIfPossible */); if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) { @@ -5020,14 +5016,16 @@ public final class ActiveServices { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e); final boolean inDestroying = mDestroyingServices.contains(r); serviceDoneExecutingLocked(r, inDestroying, inDestroying, false, - skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE); + !Flags.serviceBindingOomAdjPolicy() || r.mOomAdjBumpedInExec + ? OOM_ADJ_REASON_UNBIND_SERVICE : OOM_ADJ_REASON_NONE); throw e; } catch (RemoteException e) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r); // Keep the executeNesting count accurate. final boolean inDestroying = mDestroyingServices.contains(r); serviceDoneExecutingLocked(r, inDestroying, inDestroying, false, - skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE); + !Flags.serviceBindingOomAdjPolicy() || r.mOomAdjBumpedInExec + ? OOM_ADJ_REASON_UNBIND_SERVICE : OOM_ADJ_REASON_NONE); return false; } } @@ -5823,6 +5821,7 @@ public final class ActiveServices { // process state before doing any service related transactions mAm.enqueueOomAdjTargetLocked(app); mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE); + r.mOomAdjBumpedInExec = true; } else { // Since we skipped the oom adj update, the Service#onCreate() might be running in // the cached state, if the service process drops into the cached state after the call. @@ -5863,7 +5862,8 @@ public final class ActiveServices { // Keep the executeNesting count accurate. final boolean inDestroying = mDestroyingServices.contains(r); serviceDoneExecutingLocked(r, inDestroying, inDestroying, false, - skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_STOP_SERVICE); + !Flags.serviceBindingOomAdjPolicy() || r.mOomAdjBumpedInExec + ? OOM_ADJ_REASON_STOP_SERVICE : OOM_ADJ_REASON_NONE); // Cleanup. if (newService) { @@ -5898,7 +5898,7 @@ public final class ActiveServices { null, null, 0, null, null, ActivityManager.PROCESS_STATE_UNKNOWN)); } - sendServiceArgsLocked(r, execInFg, true); + sendServiceArgsLocked(r, execInFg, r.mOomAdjBumpedInExec); if (r.delayed) { if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "REM FR DELAY LIST (new proc): " + r); @@ -6085,7 +6085,8 @@ public final class ActiveServices { } } - boolean oomAdjusted = false; + boolean oomAdjusted = Flags.serviceBindingOomAdjPolicy() && r.mOomAdjBumpedInExec; + // Tell the service that it has been unbound. if (r.app != null && r.app.isThreadReady()) { for (int i = r.bindings.size() - 1; i >= 0; i--) { @@ -6094,9 +6095,10 @@ public final class ActiveServices { + ": hasBound=" + ibr.hasBound); if (ibr.hasBound) { try { - oomAdjusted |= bumpServiceExecutingLocked(r, false, "bring down unbind", - OOM_ADJ_REASON_UNBIND_SERVICE, - false /* skipTimeoutIfPossible */); + bumpServiceExecutingLocked(r, false, "bring down unbind", + oomAdjusted ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE, + oomAdjusted /* skipTimeoutIfPossible */); + oomAdjusted |= r.mOomAdjBumpedInExec; ibr.hasBound = false; ibr.requested = false; r.app.getThread().scheduleUnbindService(r, @@ -6252,10 +6254,11 @@ public final class ActiveServices { } } else { try { - oomAdjusted |= bumpServiceExecutingLocked(r, false, "destroy", - oomAdjusted ? 0 : OOM_ADJ_REASON_STOP_SERVICE, - false /* skipTimeoutIfPossible */); + bumpServiceExecutingLocked(r, false, "destroy", + oomAdjusted ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE, + oomAdjusted /* skipTimeoutIfPossible */); mDestroyingServices.add(r); + oomAdjusted |= r.mOomAdjBumpedInExec; r.destroying = true; r.app.getThread().scheduleStopService(r); } catch (Exception e) { @@ -6411,7 +6414,7 @@ public final class ActiveServices { final boolean skipOomAdj = (serviceBindingOomAdjPolicy & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT) != 0; try { - b.intent.mSkippedOomAdj = !bumpServiceExecutingLocked(s, false, "unbind", + bumpServiceExecutingLocked(s, false, "unbind", skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE, skipOomAdj /* skipTimeoutIfPossible */); if (b.client != s.app && c.notHasFlag(Context.BIND_WAIVE_PRIORITY) @@ -6461,6 +6464,7 @@ public final class ActiveServices { boolean inDestroying = mDestroyingServices.contains(r); if (r != null) { boolean skipOomAdj = false; + boolean needOomAdj = false; if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) { // This is a call from a service start... take care of // book-keeping. @@ -6536,15 +6540,13 @@ public final class ActiveServices { // Fake it to keep from ANR due to orphaned entry. r.executeNesting = 1; } - } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_REBIND - || type == ActivityThread.SERVICE_DONE_EXECUTING_UNBIND) { - final Intent.FilterComparison filter = new Intent.FilterComparison(intent); - final IntentBindRecord b = r.bindings.get(filter); - skipOomAdj = Flags.serviceBindingOomAdjPolicy() && b != null && b.mSkippedOomAdj; + // The service is done, force an oom adj update. + needOomAdj = true; } final long origId = mAm.mInjector.clearCallingIdentity(); serviceDoneExecutingLocked(r, inDestroying, inDestroying, enqueueOomAdj, - skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_EXECUTING_SERVICE); + !Flags.serviceBindingOomAdjPolicy() || r.mOomAdjBumpedInExec || needOomAdj + ? OOM_ADJ_REASON_EXECUTING_SERVICE : OOM_ADJ_REASON_NONE); mAm.mInjector.restoreCallingIdentity(origId); } else { Slog.w(TAG, "Done executing unknown service from pid " @@ -6600,18 +6602,16 @@ public final class ActiveServices { mDestroyingServices.remove(r); r.bindings.clear(); } - boolean oomAdjusted = false; if (oomAdjReason != OOM_ADJ_REASON_NONE) { if (enqueueOomAdj) { mAm.enqueueOomAdjTargetLocked(r.app); } else { mAm.updateOomAdjLocked(r.app, oomAdjReason); } - oomAdjusted = true; } else { // Skip oom adj if it wasn't bumped during the bumpServiceExecutingLocked() - oomAdjusted = false; } + r.mOomAdjBumpedInExec = false; } r.executeFg = false; if (r.tracker != null) { @@ -6995,6 +6995,7 @@ public final class ActiveServices { sr.setProcess(null, null, 0, null); sr.isolationHostProc = null; sr.executeNesting = 0; + sr.mOomAdjBumpedInExec = false; synchronized (mAm.mProcessStats.mLock) { sr.forceClearTracker(); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2dd2f8fde797..e222878a5dd3 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -18462,7 +18462,8 @@ public class ActivityManagerService extends IActivityManager.Stub (WindowProcessController) procsToKill.get(i); final ProcessRecord pr = (ProcessRecord) wpc.mOwner; if (ActivityManager.isProcStateBackground(pr.mState.getSetProcState()) - && pr.mReceivers.numberOfCurReceivers() == 0) { + && pr.mReceivers.numberOfCurReceivers() == 0 + && !pr.mState.hasStartedServices()) { pr.killLocked("remove task", ApplicationExitInfo.REASON_USER_REQUESTED, ApplicationExitInfo.SUBREASON_REMOVE_TASK, true); } else { diff --git a/services/core/java/com/android/server/am/IntentBindRecord.java b/services/core/java/com/android/server/am/IntentBindRecord.java index db47e3f26a6d..1a3652e49d8e 100644 --- a/services/core/java/com/android/server/am/IntentBindRecord.java +++ b/services/core/java/com/android/server/am/IntentBindRecord.java @@ -49,14 +49,6 @@ final class IntentBindRecord { String stringName; // caching of toString - /** - * Mark if we've skipped oom adj update before calling into the {@link Service#onBind()} - * or {@link Service#onUnbind()}. - * - * <p>If it's true, we'll skip the oom adj update too during the serviceDoneExecuting. - */ - boolean mSkippedOomAdj; - void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("service="); pw.println(service); dumpInService(pw, prefix); diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 9568116288b5..31328ae83f71 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -3322,7 +3322,8 @@ public class OomAdjuster { reportOomAdjMessageLocked(TAG_OOM_ADJ, msg); } if (app.getWaitingToKill() != null && app.mReceivers.numberOfCurReceivers() == 0 - && ActivityManager.isProcStateBackground(state.getSetProcState())) { + && ActivityManager.isProcStateBackground(state.getSetProcState()) + && !state.hasStartedServices()) { app.killLocked(app.getWaitingToKill(), ApplicationExitInfo.REASON_USER_REQUESTED, ApplicationExitInfo.SUBREASON_REMOVE_TASK, true); success = false; diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java index 1412259abf89..2ef433cad8ce 100644 --- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java +++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java @@ -64,6 +64,9 @@ import com.android.server.wm.WindowProcessController; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.UUID; import java.util.concurrent.ExecutionException; @@ -76,6 +79,9 @@ import java.util.concurrent.atomic.AtomicLong; * The error state of the process, such as if it's crashing/ANR etc. */ class ProcessErrorStateRecord { + private static final DateTimeFormatter DROPBOX_TIME_FORMATTER = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSZ"); + final ProcessRecord mApp; private final ActivityManagerService mService; @@ -444,6 +450,13 @@ class ProcessErrorStateRecord { info.append("ErrorId: ").append(errorId.toString()).append("\n"); } info.append("Frozen: ").append(mApp.mOptRecord.isFrozen()).append("\n"); + if (timeoutRecord != null && timeoutRecord.mEndUptimeMillis > 0) { + long millisSinceEndUptimeMs = anrTime - timeoutRecord.mEndUptimeMillis; + String formattedTime = DROPBOX_TIME_FORMATTER.format( + Instant.now().minusMillis(millisSinceEndUptimeMs) + .atZone(ZoneId.systemDefault())); + info.append("Timestamp: ").append(formattedTime).append("\n"); + } // Retrieve controller with max ANR delay from AnrControllers // Note that we retrieve the controller before dumping stacks because dumping stacks can diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 3c8d7fc833dc..e3aac0251141 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -267,6 +267,11 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN int mAllowStart_byBindings = REASON_DENIED; /** + * Whether or not we've bumped its oom adj scores during its execution. + */ + boolean mOomAdjBumpedInExec; + + /** * Whether to use the new "while-in-use permission" logic for FGS start */ private boolean useNewWiuLogic_forStart() { diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 966fe5bbeecc..d1bda7991f45 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -126,6 +126,7 @@ public class SettingsToPropertiesMapper { "arc_next", "avic", "bluetooth", + "brownout_mitigation_audio", "build", "biometrics", "biometrics_framework", diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java index 5f12ce1e4163..9f31f375dafe 100644 --- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java +++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java @@ -73,8 +73,7 @@ public class AmbientContextManagerService extends private static final Set<Integer> DEFAULT_EVENT_SET = Sets.newHashSet( AmbientContextEvent.EVENT_COUGH, AmbientContextEvent.EVENT_SNORE, - AmbientContextEvent.EVENT_BACK_DOUBLE_TAP, - AmbientContextEvent.EVENT_HEART_RATE); + AmbientContextEvent.EVENT_BACK_DOUBLE_TAP); /** Default value in absence of {@link DeviceConfig} override. */ private static final boolean DEFAULT_SERVICE_ENABLED = true; diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 0cc64941cfe6..fb627854209d 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -661,8 +661,12 @@ public class AppOpsService extends IAppOpsService.Stub { @NonNull OpEntry createEntryLocked(String persistentDeviceId) { // TODO(b/308201969): Update this method when we introduce disk persistence of events // for accesses on external devices. - final ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get( + ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get( persistentDeviceId); + if (attributedOps == null) { + attributedOps = new ArrayMap<>(); + } + final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries = new ArrayMap<>(attributedOps.size()); for (int i = 0; i < attributedOps.size(); i++) { @@ -680,8 +684,12 @@ public class AppOpsService extends IAppOpsService.Stub { @NonNull OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) { // TODO(b/308201969): Update this method when we introduce disk persistence of events // for accesses on external devices. - final ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get( + ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get( PERSISTENT_DEVICE_ID_DEFAULT); + if (attributedOps == null) { + attributedOps = new ArrayMap<>(); + } + final ArrayMap<String, AttributedOpEntry> attributionEntries = new ArrayMap<>(1); if (attributedOps.get(attributionTag) != null) { attributionEntries.put(attributionTag, diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index cb6d26f61314..19dd7b7ea2f6 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -12528,6 +12528,16 @@ public class AudioService extends IAudioService.Stub if (app == null) { return AudioManager.ERROR; } + if (android.media.audiopolicy.Flags.audioMixOwnership()) { + for (AudioMix mix : policyConfig.getMixes()) { + if (!app.getMixes().contains(mix)) { + Slog.e(TAG, + "removeMixForPolicy attempted to unregister AudioMix(es) not " + + "belonging to the AudioPolicy"); + return AudioManager.ERROR; + } + } + } return app.removeMixes(policyConfig.getMixes()) == AudioSystem.SUCCESS ? AudioManager.SUCCESS : AudioManager.ERROR; } @@ -13306,7 +13316,13 @@ public class AudioService extends IAudioService.Stub } final long identity = Binder.clearCallingIdentity(); try { - mAudioSystem.registerPolicyMixes(mMixes, false); + if (android.media.audiopolicy.Flags.audioMixOwnership()) { + synchronized (mMixes) { + removeMixes(new ArrayList(mMixes)); + } + } else { + mAudioSystem.registerPolicyMixes(mMixes, false); + } } finally { Binder.restoreCallingIdentity(identity); } @@ -13350,6 +13366,17 @@ public class AudioService extends IAudioService.Stub int addMixes(@NonNull ArrayList<AudioMix> mixes) { synchronized (mMixes) { + if (android.media.audiopolicy.Flags.audioMixOwnership()) { + for (AudioMix mix : mixes) { + setMixRegistration(mix); + } + + int result = mAudioSystem.registerPolicyMixes(mixes, true); + if (result == AudioSystem.SUCCESS) { + this.add(mixes); + } + return result; + } this.add(mixes); return mAudioSystem.registerPolicyMixes(mixes, true); } diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index 082776ad6085..fb4976d3cef2 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -16,6 +16,7 @@ package com.android.server.display; +import static com.android.server.display.BrightnessMappingStrategy.INVALID_LUX; import static com.android.server.display.config.DisplayBrightnessMappingConfig.autoBrightnessModeToString; import android.annotation.IntDef; @@ -202,7 +203,7 @@ public class AutomaticBrightnessController { private float mScreenBrighteningThreshold; private float mScreenDarkeningThreshold; // The most recent light sample. - private float mLastObservedLux; + private float mLastObservedLux = INVALID_LUX; // The time of the most light recent sample. private long mLastObservedLuxTime; @@ -403,8 +404,8 @@ public class AutomaticBrightnessController { brightnessEvent.setFlags(brightnessEvent.getFlags() | (!mAmbientLuxValid ? BrightnessEvent.FLAG_INVALID_LUX : 0) | (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE - ? BrightnessEvent.FLAG_DOZE_SCALE : 0) - | (isInIdleMode() ? BrightnessEvent.FLAG_IDLE_CURVE : 0)); + ? BrightnessEvent.FLAG_DOZE_SCALE : 0)); + brightnessEvent.setAutoBrightnessMode(getMode()); } if (!mAmbientLuxValid) { @@ -420,6 +421,35 @@ public class AutomaticBrightnessController { return mRawScreenAutoBrightness; } + /** + * Get the automatic screen brightness based on the last observed lux reading. Used e.g. when + * entering doze - we disable the light sensor, invalidate the lux, but we still need to set + * the initial brightness in doze mode. + */ + public float getAutomaticScreenBrightnessBasedOnLastObservedLux( + BrightnessEvent brightnessEvent) { + if (mLastObservedLux == INVALID_LUX) { + return PowerManager.BRIGHTNESS_INVALID_FLOAT; + } + + float brightness = mCurrentBrightnessMapper.getBrightness(mLastObservedLux, + mForegroundAppPackageName, mForegroundAppCategory); + if (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE) { + brightness *= mDozeScaleFactor; + } + + if (brightnessEvent != null) { + brightnessEvent.setLux(mLastObservedLux); + brightnessEvent.setRecommendedBrightness(brightness); + brightnessEvent.setFlags(brightnessEvent.getFlags() + | (mLastObservedLux == INVALID_LUX ? BrightnessEvent.FLAG_INVALID_LUX : 0) + | (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE + ? BrightnessEvent.FLAG_DOZE_SCALE : 0)); + brightnessEvent.setAutoBrightnessMode(getMode()); + } + return brightness; + } + public boolean hasValidAmbientLux() { return mAmbientLuxValid; } @@ -539,7 +569,7 @@ public class AutomaticBrightnessController { } private boolean setScreenBrightnessByUser(float lux, float brightness) { - if (lux == BrightnessMappingStrategy.INVALID_LUX || Float.isNaN(brightness)) { + if (lux == INVALID_LUX || Float.isNaN(brightness)) { return false; } mCurrentBrightnessMapper.addUserDataPoint(lux, brightness); @@ -564,6 +594,15 @@ public class AutomaticBrightnessController { return false; } + /** + * @return The auto-brightness mode of the current mapping strategy. Different modes use + * different brightness curves. + */ + @AutomaticBrightnessController.AutomaticBrightnessMode + public int getMode() { + return mCurrentBrightnessMapper.getMode(); + } + public boolean isInIdleMode() { return mCurrentBrightnessMapper.getMode() == AUTO_BRIGHTNESS_MODE_IDLE; } @@ -1236,12 +1275,12 @@ public class AutomaticBrightnessController { // light. // The anchor determines what were the light levels when the user has set their preference, // and we use a relative threshold to determine when to revert to the OEM curve. - private float mAnchor = BrightnessMappingStrategy.INVALID_LUX; + private float mAnchor = INVALID_LUX; private float mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; private boolean mIsValid = false; private void reset() { - mAnchor = BrightnessMappingStrategy.INVALID_LUX; + mAnchor = INVALID_LUX; mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT; mIsValid = false; } @@ -1265,7 +1304,7 @@ public class AutomaticBrightnessController { private boolean maybeReset(float currentLux) { // If the short term model was invalidated and the change is drastic enough, reset it. // Otherwise, we revalidate it. - if (!mIsValid && mAnchor != BrightnessMappingStrategy.INVALID_LUX) { + if (!mIsValid && mAnchor != INVALID_LUX) { if (mCurrentBrightnessMapper.shouldResetShortTermModel(currentLux, mAnchor)) { resetShortTermModel(); } else { diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 3965d55b0c28..dbe85ea0fa04 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -16,6 +16,8 @@ package com.android.server.display; +import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE; + import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT; import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE; import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE; @@ -37,7 +39,6 @@ import android.hardware.display.AmbientBrightnessDayStats; import android.hardware.display.BrightnessChangeEvent; import android.hardware.display.BrightnessConfiguration; import android.hardware.display.BrightnessInfo; -import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession; import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks; import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; @@ -1378,7 +1379,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // Switch to doze auto-brightness mode if needed if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null && !mAutomaticBrightnessController.isInIdleMode()) { - setAutomaticScreenBrightnessMode(Display.isDozeState(state) + mAutomaticBrightnessController.switchMode(mPowerRequest.policy == POLICY_DOZE ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT); } @@ -1466,6 +1467,22 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mAutomaticBrightnessStrategy.setAutoBrightnessApplied(false); } + // If there's an offload session and auto-brightness is on, we need to set the initial doze + // brightness using the doze auto-brightness curve before the offload session starts + // controlling the brightness. + if (Float.isNaN(brightnessState) && mFlags.areAutoBrightnessModesEnabled() + && mFlags.isDisplayOffloadEnabled() + && mPowerRequest.policy == POLICY_DOZE + && mDisplayOffloadSession != null + && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) { + rawBrightnessState = mAutomaticBrightnessController + .getAutomaticScreenBrightnessBasedOnLastObservedLux(mTempBrightnessEvent); + if (BrightnessUtils.isValidBrightnessValue(rawBrightnessState)) { + brightnessState = clampScreenBrightness(rawBrightnessState); + mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_INITIAL); + } + } + // Use default brightness when dozing unless overridden. if ((Float.isNaN(brightnessState)) && Display.isDozeState(state)) { @@ -1618,7 +1635,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // if doze or suspend state is requested, we want to finish brightnes animation fast // to allow state animation to start - if (mPowerRequest.policy == DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE + if (mPowerRequest.policy == POLICY_DOZE && (mPowerRequest.dozeScreenState == Display.STATE_UNKNOWN // dozing || mPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND || mPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND)) { @@ -1706,6 +1723,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mTempBrightnessEvent.setTime(System.currentTimeMillis()); mTempBrightnessEvent.setBrightness(brightnessState); mTempBrightnessEvent.setPhysicalDisplayId(mUniqueDisplayId); + mTempBrightnessEvent.setDisplayState(state); mTempBrightnessEvent.setReason(mBrightnessReason); mTempBrightnessEvent.setHbmMax(mBrightnessRangeController.getCurrentBrightnessMax()); mTempBrightnessEvent.setHbmMode(mBrightnessRangeController.getHighBrightnessMode()); @@ -2879,7 +2897,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call (flags & BrightnessEvent.FLAG_INVALID_LUX) > 0, (flags & BrightnessEvent.FLAG_DOZE_SCALE) > 0, (flags & BrightnessEvent.FLAG_USER_SET) > 0, - (flags & BrightnessEvent.FLAG_IDLE_CURVE) > 0, + event.getAutoBrightnessMode() == AUTO_BRIGHTNESS_MODE_IDLE, (flags & BrightnessEvent.FLAG_LOW_POWER_MODE) > 0); } } diff --git a/services/core/java/com/android/server/display/brightness/BrightnessEvent.java b/services/core/java/com/android/server/display/brightness/BrightnessEvent.java index d4d1bae78a33..5423b74711a2 100644 --- a/services/core/java/com/android/server/display/brightness/BrightnessEvent.java +++ b/services/core/java/com/android/server/display/brightness/BrightnessEvent.java @@ -16,11 +16,16 @@ package com.android.server.display.brightness; +import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT; +import static com.android.server.display.config.DisplayBrightnessMappingConfig.autoBrightnessModeToString; + import android.hardware.display.BrightnessInfo; import android.os.PowerManager; import android.os.SystemClock; +import android.view.Display; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.display.AutomaticBrightnessController; import java.text.SimpleDateFormat; import java.util.Date; @@ -33,7 +38,6 @@ public final class BrightnessEvent { public static final int FLAG_INVALID_LUX = 0x2; public static final int FLAG_DOZE_SCALE = 0x4; public static final int FLAG_USER_SET = 0x8; - public static final int FLAG_IDLE_CURVE = 0x10; public static final int FLAG_LOW_POWER_MODE = 0x20; private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS"); @@ -41,6 +45,7 @@ public final class BrightnessEvent { private BrightnessReason mReason = new BrightnessReason(); private int mDisplayId; private String mPhysicalDisplayId; + private int mDisplayState; private long mTime; private float mLux; private float mPreThresholdLux; @@ -58,6 +63,8 @@ public final class BrightnessEvent { private int mAdjustmentFlags; private boolean mAutomaticBrightnessEnabled; private String mDisplayBrightnessStrategyName; + @AutomaticBrightnessController.AutomaticBrightnessMode + private int mAutoBrightnessMode; public BrightnessEvent(BrightnessEvent that) { copyFrom(that); @@ -77,6 +84,7 @@ public final class BrightnessEvent { mReason.set(that.getReason()); mDisplayId = that.getDisplayId(); mPhysicalDisplayId = that.getPhysicalDisplayId(); + mDisplayState = that.mDisplayState; mTime = that.getTime(); // Lux values mLux = that.getLux(); @@ -98,6 +106,7 @@ public final class BrightnessEvent { // Auto-brightness setting mAutomaticBrightnessEnabled = that.isAutomaticBrightnessEnabled(); mDisplayBrightnessStrategyName = that.getDisplayBrightnessStrategyName(); + mAutoBrightnessMode = that.mAutoBrightnessMode; } /** @@ -107,6 +116,7 @@ public final class BrightnessEvent { mReason = new BrightnessReason(); mTime = SystemClock.uptimeMillis(); mPhysicalDisplayId = ""; + mDisplayState = Display.STATE_UNKNOWN; // Lux values mLux = 0; mPreThresholdLux = 0; @@ -127,6 +137,7 @@ public final class BrightnessEvent { // Auto-brightness setting mAutomaticBrightnessEnabled = true; mDisplayBrightnessStrategyName = ""; + mAutoBrightnessMode = AUTO_BRIGHTNESS_MODE_DEFAULT; } /** @@ -143,6 +154,7 @@ public final class BrightnessEvent { return mReason.equals(that.mReason) && mDisplayId == that.mDisplayId && mPhysicalDisplayId.equals(that.mPhysicalDisplayId) + && mDisplayState == that.mDisplayState && Float.floatToRawIntBits(mLux) == Float.floatToRawIntBits(that.mLux) && Float.floatToRawIntBits(mPreThresholdLux) == Float.floatToRawIntBits(that.mPreThresholdLux) @@ -163,7 +175,8 @@ public final class BrightnessEvent { && mFlags == that.mFlags && mAdjustmentFlags == that.mAdjustmentFlags && mAutomaticBrightnessEnabled == that.mAutomaticBrightnessEnabled - && mDisplayBrightnessStrategyName.equals(that.mDisplayBrightnessStrategyName); + && mDisplayBrightnessStrategyName.equals(that.mDisplayBrightnessStrategyName) + && mAutoBrightnessMode == that.mAutoBrightnessMode; } /** @@ -177,6 +190,7 @@ public final class BrightnessEvent { + "BrightnessEvent: " + "disp=" + mDisplayId + ", physDisp=" + mPhysicalDisplayId + + ", displayState=" + Display.stateToString(mDisplayState) + ", brt=" + mBrightness + ((mFlags & FLAG_USER_SET) != 0 ? "(user_set)" : "") + ", initBrt=" + mInitialBrightness + ", rcmdBrt=" + mRecommendedBrightness @@ -192,7 +206,8 @@ public final class BrightnessEvent { + ", flags=" + flagsToString() + ", reason=" + mReason.toString(mAdjustmentFlags) + ", autoBrightness=" + mAutomaticBrightnessEnabled - + ", strategy=" + mDisplayBrightnessStrategyName; + + ", strategy=" + mDisplayBrightnessStrategyName + + ", autoBrightnessMode=" + autoBrightnessModeToString(mAutoBrightnessMode); } @Override @@ -232,6 +247,10 @@ public final class BrightnessEvent { this.mPhysicalDisplayId = mPhysicalDisplayId; } + public void setDisplayState(int state) { + mDisplayState = state; + } + public float getLux() { return mLux; } @@ -374,6 +393,16 @@ public final class BrightnessEvent { this.mAutomaticBrightnessEnabled = mAutomaticBrightnessEnabled; } + @AutomaticBrightnessController.AutomaticBrightnessMode + public int getAutoBrightnessMode() { + return mAutoBrightnessMode; + } + + public void setAutoBrightnessMode( + @AutomaticBrightnessController.AutomaticBrightnessMode int mode) { + mAutoBrightnessMode = mode; + } + /** * A utility to stringify flags from a BrightnessEvent * @return Stringified flags from BrightnessEvent @@ -384,7 +413,6 @@ public final class BrightnessEvent { + ((mFlags & FLAG_RBC) != 0 ? "rbc " : "") + ((mFlags & FLAG_INVALID_LUX) != 0 ? "invalid_lux " : "") + ((mFlags & FLAG_DOZE_SCALE) != 0 ? "doze_scale " : "") - + ((mFlags & FLAG_IDLE_CURVE) != 0 ? "idle_curve " : "") + ((mFlags & FLAG_LOW_POWER_MODE) != 0 ? "low_power_mode " : ""); } } diff --git a/services/core/java/com/android/server/display/brightness/BrightnessReason.java b/services/core/java/com/android/server/display/brightness/BrightnessReason.java index bc443a8167ab..fc95d15ae6f4 100644 --- a/services/core/java/com/android/server/display/brightness/BrightnessReason.java +++ b/services/core/java/com/android/server/display/brightness/BrightnessReason.java @@ -40,7 +40,8 @@ public final class BrightnessReason { public static final int REASON_SCREEN_OFF_BRIGHTNESS_SENSOR = 9; public static final int REASON_FOLLOWER = 10; public static final int REASON_OFFLOAD = 11; - public static final int REASON_MAX = REASON_OFFLOAD; + public static final int REASON_DOZE_INITIAL = 12; + public static final int REASON_MAX = REASON_DOZE_INITIAL; public static final int MODIFIER_DIMMED = 0x1; public static final int MODIFIER_LOW_POWER = 0x2; @@ -207,6 +208,8 @@ public final class BrightnessReason { return "follower"; case REASON_OFFLOAD: return "offload"; + case REASON_DOZE_INITIAL: + return "doze_initial"; default: return Integer.toString(reason); } diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java index 055f94a23363..babc36efcca8 100644 --- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java +++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java @@ -71,6 +71,8 @@ public class DisplayBrightnessStrategySelector { @Nullable private final OffloadBrightnessStrategy mOffloadBrightnessStrategy; + private final DisplayBrightnessStrategy[] mDisplayBrightnessStrategies; + // We take note of the old brightness strategy so that we can know when the strategy changes. private String mOldBrightnessStrategyName; @@ -98,6 +100,10 @@ public class DisplayBrightnessStrategySelector { } else { mOffloadBrightnessStrategy = null; } + mDisplayBrightnessStrategies = new DisplayBrightnessStrategy[]{mInvalidBrightnessStrategy, + mScreenOffBrightnessStrategy, mDozeBrightnessStrategy, mFollowerBrightnessStrategy, + mBoostBrightnessStrategy, mOverrideBrightnessStrategy, mTemporaryBrightnessStrategy, + mOffloadBrightnessStrategy}; mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean( R.bool.config_allowAutoBrightnessWhileDozing); mOldBrightnessStrategyName = mInvalidBrightnessStrategy.getName(); @@ -179,9 +185,10 @@ public class DisplayBrightnessStrategySelector { " mAllowAutoBrightnessWhileDozingConfig= " + mAllowAutoBrightnessWhileDozingConfig); IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " "); - mTemporaryBrightnessStrategy.dump(ipw); - if (mOffloadBrightnessStrategy != null) { - mOffloadBrightnessStrategy.dump(ipw); + for (DisplayBrightnessStrategy displayBrightnessStrategy: mDisplayBrightnessStrategies) { + if (displayBrightnessStrategy != null) { + displayBrightnessStrategy.dump(ipw); + } } } diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java index 3e6e09da9753..8eaecef6e562 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java @@ -267,6 +267,23 @@ public class AutomaticBrightnessStrategy { } /** + * Get the automatic screen brightness based on the last observed lux reading. Used e.g. when + * entering doze - we disable the light sensor, invalidate the lux, but we still need to set + * the initial brightness in doze mode. + * @param brightnessEvent Event object to populate with details about why the specific + * brightness was chosen. + */ + public float getAutomaticScreenBrightnessBasedOnLastObservedLux( + BrightnessEvent brightnessEvent) { + float brightness = (mAutomaticBrightnessController != null) + ? mAutomaticBrightnessController + .getAutomaticScreenBrightnessBasedOnLastObservedLux(brightnessEvent) + : PowerManager.BRIGHTNESS_INVALID_FLOAT; + adjustAutomaticBrightnessStateIfValid(brightness); + return brightness; + } + + /** * Gets the auto-brightness adjustment flag change reason */ public int getAutoBrightnessAdjustmentReasonsFlags() { diff --git a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java index dd400d998eb4..9ee1d73726bd 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java @@ -23,6 +23,8 @@ import com.android.server.display.DisplayBrightnessState; import com.android.server.display.brightness.BrightnessReason; import com.android.server.display.brightness.BrightnessUtils; +import java.io.PrintWriter; + /** * Manages the brightness of the display when the system brightness boost is requested. */ @@ -48,4 +50,7 @@ public class BoostBrightnessStrategy implements DisplayBrightnessStrategy { public String getName() { return "BoostBrightnessStrategy"; } + + @Override + public void dump(PrintWriter writer) {} } diff --git a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java index 27d04fd7f743..1f28eb4fa113 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java @@ -21,6 +21,8 @@ import android.hardware.display.DisplayManagerInternal; import com.android.server.display.DisplayBrightnessState; +import java.io.PrintWriter; + /** * Decides the DisplayBrighntessState that the display should change to based on strategy-specific * logic within each implementation. Clamping should be done outside of DisplayBrightnessStrategy if @@ -40,4 +42,10 @@ public interface DisplayBrightnessStrategy { */ @NonNull String getName(); + + /** + * Dumps the state of the Strategy + * @param writer + */ + void dump(PrintWriter writer); } diff --git a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java index 8299586e1cac..2be74438f87a 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java @@ -22,6 +22,8 @@ import com.android.server.display.DisplayBrightnessState; import com.android.server.display.brightness.BrightnessReason; import com.android.server.display.brightness.BrightnessUtils; +import java.io.PrintWriter; + /** * Manages the brightness of the display when the system is in the doze state. */ @@ -42,4 +44,6 @@ public class DozeBrightnessStrategy implements DisplayBrightnessStrategy { return "DozeBrightnessStrategy"; } + @Override + public void dump(PrintWriter writer) {} } diff --git a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java index 585f576c25c3..54f9afcbdd94 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/FollowerBrightnessStrategy.java @@ -75,6 +75,7 @@ public class FollowerBrightnessStrategy implements DisplayBrightnessStrategy { /** * Dumps the state of this class. */ + @Override public void dump(PrintWriter writer) { writer.println("FollowerBrightnessStrategy:"); writer.println(" mDisplayId=" + mDisplayId); diff --git a/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java index bc241964ff86..49c3e03c8742 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java @@ -23,6 +23,8 @@ import com.android.server.display.DisplayBrightnessState; import com.android.server.display.brightness.BrightnessReason; import com.android.server.display.brightness.BrightnessUtils; +import java.io.PrintWriter; + /** * Manages the brightness of the display when the system is in the invalid state. */ @@ -39,4 +41,7 @@ public class InvalidBrightnessStrategy implements DisplayBrightnessStrategy { public String getName() { return "InvalidBrightnessStrategy"; } + + @Override + public void dump(PrintWriter writer) {} } diff --git a/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java index 55f8914e26f6..4ffb16be5789 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/OffloadBrightnessStrategy.java @@ -67,6 +67,7 @@ public class OffloadBrightnessStrategy implements DisplayBrightnessStrategy { /** * Dumps the state of this class. */ + @Override public void dump(PrintWriter writer) { writer.println("OffloadBrightnessStrategy:"); writer.println(" mOffloadScreenBrightness:" + mOffloadScreenBrightness); diff --git a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java index 13327cb4dd2f..7b651d8ced8e 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/OverrideBrightnessStrategy.java @@ -22,6 +22,8 @@ import com.android.server.display.DisplayBrightnessState; import com.android.server.display.brightness.BrightnessReason; import com.android.server.display.brightness.BrightnessUtils; +import java.io.PrintWriter; + /** * Manages the brightness of the display when the system brightness is overridden */ @@ -40,4 +42,7 @@ public class OverrideBrightnessStrategy implements DisplayBrightnessStrategy { public String getName() { return "OverrideBrightnessStrategy"; } + + @Override + public void dump(PrintWriter writer) {} } diff --git a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java index 3d411d3db658..201ef4118854 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java @@ -23,6 +23,8 @@ import com.android.server.display.DisplayBrightnessState; import com.android.server.display.brightness.BrightnessReason; import com.android.server.display.brightness.BrightnessUtils; +import java.io.PrintWriter; + /** * Manages the brightness of the display when the system is in the ScreenOff state. */ @@ -41,4 +43,7 @@ public class ScreenOffBrightnessStrategy implements DisplayBrightnessStrategy { public String getName() { return "ScreenOffBrightnessStrategy"; } + + @Override + public void dump(PrintWriter writer) {} } diff --git a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java index 35f7dd0a524d..bbd0c009debb 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java @@ -68,6 +68,7 @@ public class TemporaryBrightnessStrategy implements DisplayBrightnessStrategy { /** * Dumps the state of this class. */ + @Override public void dump(PrintWriter writer) { writer.println("TemporaryBrightnessStrategy:"); writer.println(" mTemporaryScreenBrightness:" + mTemporaryScreenBrightness); diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index d2aff254890d..c6d66db3f8cd 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -67,6 +67,7 @@ import android.view.Display; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLoggerImpl; import com.android.internal.util.DumpUtils; @@ -112,7 +113,7 @@ public final class DreamManagerService extends SystemService { private final Object mLock = new Object(); private final Context mContext; - private final DreamHandler mHandler; + private final Handler mHandler; private final DreamController mController; private final PowerManager mPowerManager; private final PowerManagerInternal mPowerManagerInternal; @@ -211,9 +212,14 @@ public final class DreamManagerService extends SystemService { } public DreamManagerService(Context context) { + this(context, new DreamHandler(FgThread.get().getLooper())); + } + + @VisibleForTesting + DreamManagerService(Context context, Handler handler) { super(context); mContext = context; - mHandler = new DreamHandler(FgThread.get().getLooper()); + mHandler = handler; mController = new DreamController(context, mHandler, mControllerListener); mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); @@ -244,7 +250,6 @@ public final class DreamManagerService extends SystemService { com.android.internal.R.bool.config_keepDreamingWhenUnplugging); mDreamsDisabledByAmbientModeSuppressionConfig = mContext.getResources().getBoolean( com.android.internal.R.bool.config_dreamsDisabledByAmbientModeSuppressionConfig); - } @Override diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index 70993ca3e21b..1e90ab279d32 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -317,6 +317,10 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { if ((systemAudioOnPowerOnProp == ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON) || ((systemAudioOnPowerOnProp == USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON) && lastSystemAudioControlStatus && isSystemAudioControlFeatureEnabled())) { + if (hasAction(SystemAudioInitiationActionFromAvr.class)) { + Slog.i(TAG, "SystemAudioInitiationActionFromAvr is in progress. Restarting."); + removeAction(SystemAudioInitiationActionFromAvr.class); + } addAndStartAction(new SystemAudioInitiationActionFromAvr(this)); } } @@ -1032,6 +1036,10 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { void onSystemAudioControlFeatureSupportChanged(boolean enabled) { setSystemAudioControlFeatureEnabled(enabled); if (enabled) { + if (hasAction(SystemAudioInitiationActionFromAvr.class)) { + Slog.i(TAG, "SystemAudioInitiationActionFromAvr is in progress. Restarting."); + removeAction(SystemAudioInitiationActionFromAvr.class); + } addAndStartAction(new SystemAudioInitiationActionFromAvr(this)); } } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 32e89bcd1d21..a79e7715f064 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -38,7 +38,6 @@ import android.graphics.PointF; import android.hardware.SensorPrivacyManager; import android.hardware.SensorPrivacyManager.Sensors; import android.hardware.SensorPrivacyManagerInternal; -import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayViewport; import android.hardware.input.HostUsiVersion; @@ -86,9 +85,7 @@ import android.util.Log; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; -import android.util.SparseIntArray; import android.view.Display; -import android.view.DisplayInfo; import android.view.IInputFilter; import android.view.IInputFilterHost; import android.view.IInputMonitorHost; @@ -324,6 +321,9 @@ public class InputManagerService extends IInputManager.Stub // Manages Keyboard modifier keys remapping private final KeyRemapper mKeyRemapper; + // Manages loading PointerIcons + private final PointerIconCache mPointerIconCache; + // Maximum number of milliseconds to wait for input event injection. private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000; @@ -410,74 +410,6 @@ public class InputManagerService extends IInputManager.Stub private boolean mShowKeyPresses = false; private boolean mShowRotaryInput = false; - @GuardedBy("mLoadedPointerIconsByDisplayAndType") - final SparseArray<SparseArray<PointerIcon>> mLoadedPointerIconsByDisplayAndType = - new SparseArray<>(); - @GuardedBy("mLoadedPointerIconsByDisplayAndType") - boolean mUseLargePointerIcons = false; - @GuardedBy("mLoadedPointerIconsByDisplayAndType") - final SparseArray<Context> mDisplayContexts = new SparseArray<>(); - @GuardedBy("mLoadedPointerIconsByDisplayAndType") - final SparseIntArray mDisplayDensities = new SparseIntArray(); - - final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() { - @Override - public void onDisplayAdded(int displayId) { - synchronized (mLoadedPointerIconsByDisplayAndType) { - updateDisplayDensity(displayId); - } - } - - @Override - public void onDisplayRemoved(int displayId) { - synchronized (mLoadedPointerIconsByDisplayAndType) { - mLoadedPointerIconsByDisplayAndType.remove(displayId); - mDisplayContexts.remove(displayId); - mDisplayDensities.delete(displayId); - } - } - - @Override - public void onDisplayChanged(int displayId) { - synchronized (mLoadedPointerIconsByDisplayAndType) { - if (!updateDisplayDensity(displayId)) { - return; - } - // The display density changed, so force all cached pointer icons to be - // reloaded for the display. - Slog.i(TAG, - "Reloading pointer icons due to density change on display: " + displayId); - var iconsByType = mLoadedPointerIconsByDisplayAndType.get(displayId); - if (iconsByType == null) { - return; - } - iconsByType.clear(); - mDisplayContexts.remove(displayId); - } - mNative.reloadPointerIcons(); - } - - // Updates the cached display density for the given displayId, and returns true if - // the cached density changed. - @GuardedBy("mLoadedPointerIconsByDisplayAndType") - private boolean updateDisplayDensity(int displayId) { - final DisplayManager displayManager = Objects.requireNonNull( - mContext.getSystemService(DisplayManager.class)); - final Display display = displayManager.getDisplay(displayId); - if (display == null) { - return false; - } - DisplayInfo info = new DisplayInfo(); - display.getDisplayInfo(info); - final int oldDensity = mDisplayDensities.get(displayId, 0 /* default */); - if (oldDensity == info.logicalDensityDpi) { - return false; - } - mDisplayDensities.put(displayId, info.logicalDensityDpi); - return true; - } - }; - /** Point of injection for test dependencies. */ @VisibleForTesting static class Injector { @@ -536,6 +468,7 @@ public class InputManagerService extends IInputManager.Stub : new KeyboardBacklightControllerInterface() {}; mStickyModifierStateController = new StickyModifierStateController(); mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper()); + mPointerIconCache = new PointerIconCache(mContext, mNative); mUseDevInputEventForAudioJack = mContext.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); @@ -645,18 +578,11 @@ public class InputManagerService extends IInputManager.Stub mWiredAccessoryCallbacks.systemReady(); } - final DisplayManager displayManager = Objects.requireNonNull( - mContext.getSystemService(DisplayManager.class)); - displayManager.registerDisplayListener(mDisplayListener, mHandler); - final Display[] displays = displayManager.getDisplays(); - for (int i = 0; i < displays.length; i++) { - mDisplayListener.onDisplayAdded(displays[i].getDisplayId()); - } - mKeyboardLayoutManager.systemRunning(); mBatteryController.systemRunning(); mKeyboardBacklightController.systemRunning(); mKeyRemapper.systemRunning(); + mPointerIconCache.systemRunning(); } private void reloadDeviceAliases() { @@ -2410,8 +2336,8 @@ public class InputManagerService extends IInputManager.Stub synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ } synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ } synchronized (mAdditionalDisplayInputPropertiesLock) { /* Test if blocked by props lock */ } - synchronized (mLoadedPointerIconsByDisplayAndType) { /* Test if blocked by pointer lock */} mBatteryController.monitor(); + mPointerIconCache.monitor(); mNative.monitor(); } @@ -2805,21 +2731,7 @@ public class InputManagerService extends IInputManager.Stub // Native callback. @SuppressWarnings("unused") private @NonNull PointerIcon getLoadedPointerIcon(int displayId, int type) { - synchronized (mLoadedPointerIconsByDisplayAndType) { - SparseArray<PointerIcon> iconsByType = mLoadedPointerIconsByDisplayAndType.get( - displayId); - if (iconsByType == null) { - iconsByType = new SparseArray<>(); - mLoadedPointerIconsByDisplayAndType.put(displayId, iconsByType); - } - PointerIcon icon = iconsByType.get(type); - if (icon == null) { - icon = PointerIcon.getLoadedSystemIcon(getContextForDisplay(displayId), type, - mUseLargePointerIcons); - iconsByType.put(type, icon); - } - return Objects.requireNonNull(icon); - } + return mPointerIconCache.getLoadedPointerIcon(displayId, type); } // Native callback. @@ -2832,33 +2744,6 @@ public class InputManagerService extends IInputManager.Stub return sc.mNativeObject; } - @GuardedBy("mLoadedPointerIconsByDisplayAndType") - @NonNull - private Context getContextForDisplay(int displayId) { - if (displayId == Display.INVALID_DISPLAY) { - // Fallback to using the default context. - return mContext; - } - if (displayId == mContext.getDisplay().getDisplayId()) { - return mContext; - } - - Context displayContext = mDisplayContexts.get(displayId); - if (displayContext == null) { - final DisplayManager displayManager = Objects.requireNonNull( - mContext.getSystemService(DisplayManager.class)); - final Display display = displayManager.getDisplay(displayId); - if (display == null) { - // Fallback to using the default context. - return mContext; - } - - displayContext = mContext.createDisplayContext(display); - mDisplayContexts.put(displayId, displayContext); - } - return displayContext; - } - // Native callback. @SuppressWarnings("unused") private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier, String languageTag, @@ -3664,15 +3549,7 @@ public class InputManagerService extends IInputManager.Stub } void setUseLargePointerIcons(boolean useLargeIcons) { - synchronized (mLoadedPointerIconsByDisplayAndType) { - if (mUseLargePointerIcons == useLargeIcons) { - return; - } - mUseLargePointerIcons = useLargeIcons; - // Clear all cached icons on all displays. - mLoadedPointerIconsByDisplayAndType.clear(); - } - mNative.reloadPointerIcons(); + mPointerIconCache.setUseLargePointerIcons(useLargeIcons); } interface KeyboardBacklightControllerInterface { diff --git a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java index 4b9f2cf9d0c0..277a4d40c7e4 100644 --- a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java +++ b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java @@ -231,7 +231,10 @@ public final class KeyboardMetricsCollector { DESKTOP_MODE( FrameworkStatsLog .KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE, - "DESKTOP_MODE"); + "DESKTOP_MODE"), + MULTI_WINDOW_NAVIGATION(FrameworkStatsLog + .KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION, + "MULTIWINDOW_NAVIGATION"); private final int mValue; diff --git a/services/core/java/com/android/server/input/PointerIconCache.java b/services/core/java/com/android/server/input/PointerIconCache.java new file mode 100644 index 000000000000..233b865c69a6 --- /dev/null +++ b/services/core/java/com/android/server/input/PointerIconCache.java @@ -0,0 +1,207 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.input; + +import android.annotation.NonNull; +import android.content.Context; +import android.hardware.display.DisplayManager; +import android.os.Handler; +import android.util.Slog; +import android.util.SparseArray; +import android.util.SparseIntArray; +import android.view.Display; +import android.view.DisplayInfo; +import android.view.PointerIcon; + +import com.android.internal.annotations.GuardedBy; +import com.android.server.UiThread; + +import java.util.Objects; + +/** + * A thread-safe component of {@link InputManagerService} responsible for caching loaded + * {@link PointerIcon}s and triggering reloading of the icons. + */ +final class PointerIconCache { + private static final String TAG = PointerIconCache.class.getSimpleName(); + + private final Context mContext; + + // Do not hold the lock when calling into native code. + private final NativeInputManagerService mNative; + + // We use the UI thread for loading pointer icons. + private final Handler mUiThreadHandler = UiThread.getHandler(); + + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private final SparseArray<SparseArray<PointerIcon>> mLoadedPointerIconsByDisplayAndType = + new SparseArray<>(); + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private boolean mUseLargePointerIcons = false; + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private final SparseArray<Context> mDisplayContexts = new SparseArray<>(); + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private final SparseIntArray mDisplayDensities = new SparseIntArray(); + + private final DisplayManager.DisplayListener mDisplayListener = + new DisplayManager.DisplayListener() { + @Override + public void onDisplayAdded(int displayId) { + synchronized (mLoadedPointerIconsByDisplayAndType) { + updateDisplayDensityLocked(displayId); + } + } + + @Override + public void onDisplayRemoved(int displayId) { + synchronized (mLoadedPointerIconsByDisplayAndType) { + mLoadedPointerIconsByDisplayAndType.remove(displayId); + mDisplayContexts.remove(displayId); + mDisplayDensities.delete(displayId); + } + } + + @Override + public void onDisplayChanged(int displayId) { + handleDisplayChanged(displayId); + } + }; + + /* package */ PointerIconCache(Context context, NativeInputManagerService nativeService) { + mContext = context; + mNative = nativeService; + } + + public void systemRunning() { + final DisplayManager displayManager = Objects.requireNonNull( + mContext.getSystemService(DisplayManager.class)); + displayManager.registerDisplayListener(mDisplayListener, mUiThreadHandler); + final Display[] displays = displayManager.getDisplays(); + for (int i = 0; i < displays.length; i++) { + mDisplayListener.onDisplayAdded(displays[i].getDisplayId()); + } + } + + public void monitor() { + synchronized (mLoadedPointerIconsByDisplayAndType) { /* Test if blocked by lock */} + } + + /** Set whether the large pointer icons should be used for accessibility. */ + public void setUseLargePointerIcons(boolean useLargeIcons) { + mUiThreadHandler.post(() -> handleSetUseLargePointerIcons(useLargeIcons)); + } + + /** + * Get a loaded system pointer icon. This will fetch the icon from the cache, or load it if + * it isn't already cached. + */ + public @NonNull PointerIcon getLoadedPointerIcon(int displayId, int type) { + synchronized (mLoadedPointerIconsByDisplayAndType) { + SparseArray<PointerIcon> iconsByType = mLoadedPointerIconsByDisplayAndType.get( + displayId); + if (iconsByType == null) { + iconsByType = new SparseArray<>(); + mLoadedPointerIconsByDisplayAndType.put(displayId, iconsByType); + } + PointerIcon icon = iconsByType.get(type); + if (icon == null) { + icon = PointerIcon.getLoadedSystemIcon(getContextForDisplayLocked(displayId), type, + mUseLargePointerIcons); + iconsByType.put(type, icon); + } + return Objects.requireNonNull(icon); + } + } + + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private @NonNull Context getContextForDisplayLocked(int displayId) { + if (displayId == Display.INVALID_DISPLAY) { + // Fallback to using the default context. + return mContext; + } + if (displayId == mContext.getDisplay().getDisplayId()) { + return mContext; + } + + Context displayContext = mDisplayContexts.get(displayId); + if (displayContext == null) { + final DisplayManager displayManager = Objects.requireNonNull( + mContext.getSystemService(DisplayManager.class)); + final Display display = displayManager.getDisplay(displayId); + if (display == null) { + // Fallback to using the default context. + return mContext; + } + + displayContext = mContext.createDisplayContext(display); + mDisplayContexts.put(displayId, displayContext); + } + return displayContext; + } + + @android.annotation.UiThread + private void handleDisplayChanged(int displayId) { + synchronized (mLoadedPointerIconsByDisplayAndType) { + if (!updateDisplayDensityLocked(displayId)) { + return; + } + // The display density changed, so force all cached pointer icons to be + // reloaded for the display. + Slog.i(TAG, "Reloading pointer icons due to density change on display: " + displayId); + var iconsByType = mLoadedPointerIconsByDisplayAndType.get(displayId); + if (iconsByType == null) { + return; + } + iconsByType.clear(); + mDisplayContexts.remove(displayId); + } + mNative.reloadPointerIcons(); + } + + @android.annotation.UiThread + private void handleSetUseLargePointerIcons(boolean useLargeIcons) { + synchronized (mLoadedPointerIconsByDisplayAndType) { + if (mUseLargePointerIcons == useLargeIcons) { + return; + } + mUseLargePointerIcons = useLargeIcons; + // Clear all cached icons on all displays. + mLoadedPointerIconsByDisplayAndType.clear(); + } + mNative.reloadPointerIcons(); + } + + // Updates the cached display density for the given displayId, and returns true if + // the cached density changed. + @GuardedBy("mLoadedPointerIconsByDisplayAndType") + private boolean updateDisplayDensityLocked(int displayId) { + final DisplayManager displayManager = Objects.requireNonNull( + mContext.getSystemService(DisplayManager.class)); + final Display display = displayManager.getDisplay(displayId); + if (display == null) { + return false; + } + DisplayInfo info = new DisplayInfo(); + display.getDisplayInfo(info); + final int oldDensity = mDisplayDensities.get(displayId, 0 /* default */); + if (oldDensity == info.logicalDensityDpi) { + return false; + } + mDisplayDensities.put(displayId, info.logicalDensityDpi); + return true; + } +} diff --git a/services/core/java/com/android/server/inputmethod/ClientController.java b/services/core/java/com/android/server/inputmethod/ClientController.java index 86f4db959409..0381a317de5f 100644 --- a/services/core/java/com/android/server/inputmethod/ClientController.java +++ b/services/core/java/com/android/server/inputmethod/ClientController.java @@ -33,36 +33,10 @@ import java.util.List; import java.util.function.Consumer; /** - * Store and manage {@link InputMethodManagerService} clients. This class was designed to be a - * singleton in {@link InputMethodManagerService} since it stores information about all clients, - * still the current client will be defined per display. - * - * <p> - * As part of the re-architecture plan (described in go/imms-rearchitecture-plan), the following - * fields and methods will be moved out from IMMS and placed here: - * <ul> - * <li>mClients (ArrayMap of ClientState indexed by IBinder)</li> - * </ul> - * <p> - * Nested Classes (to move from IMMS): - * <ul> - * <li>ClientDeathRecipient</li> - * <li>ClientState<</li> - * </ul> - * <p> - * Methods to rewrite and/or extract from IMMS and move here: - * <ul> - * <li>addClient</li> - * <li>removeClient</li> - * <li>verifyClientAndPackageMatch</li> - * <li>setImeTraceEnabledForAllClients (make it reactive)</li> - * </ul> + * Store and manage {@link InputMethodManagerService} clients. */ -// TODO(b/314150112): Update the Javadoc above, by removing the re-architecture steps, once this -// class is finalized final class ClientController { - // TODO(b/314150112): Make this field private when breaking the cycle with IMMS. @GuardedBy("ImfLock.class") private final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>(); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 76956c88695d..307b70a89634 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2193,7 +2193,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } - // TODO(b/314150112): Move this method to InputMethodBindingController + // TODO(b/325515685): Move this method to InputMethodBindingController /** * Hide the IME if the removed user is the current user. */ diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index 75be0684c8f4..a608049cd677 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -463,11 +463,13 @@ public class LocationManagerService extends ILocationManager.Stub implements com.android.internal.R.bool.config_useGnssHardwareProvider); AbstractLocationProvider gnssProvider = null; if (!useGnssHardwareProvider) { + // TODO: Create a separate config_enableGnssLocationOverlay config resource + // if we want to selectively enable a GNSS overlay but disable a fused overlay. gnssProvider = ProxyLocationProvider.create( mContext, GPS_PROVIDER, ACTION_GNSS_PROVIDER, - com.android.internal.R.bool.config_useGnssHardwareProvider, + com.android.internal.R.bool.config_enableFusedLocationOverlay, com.android.internal.R.string.config_gnssLocationProviderPackageName); } if (gnssProvider == null) { diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java index ecb4fcca5eef..40e538b02728 100644 --- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java +++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java @@ -1618,6 +1618,17 @@ public class LocationProviderManager extends */ @SuppressLint("AndroidFrameworkRequiresPermission") public boolean isVisibleToCaller() { + // Anything sharing the system's UID can view all providers + if (Binder.getCallingUid() == Process.SYSTEM_UID) { + return true; + } + + // If an app mocked this provider, anybody can access it (the goal is + // to behave as if this provider didn't naturally exist). + if (mProvider.isMock()) { + return true; + } + for (String permission : mRequiredPermissions) { if (mContext.checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) { return false; diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index b5c51af47009..31bfc6954416 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -727,7 +727,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * Map of uid -> UidStateCallbackInfo objects holding the data received from * {@link IUidObserver#onUidStateChanged(int, int, long, int)} callbacks. In order to avoid * creating a new object for every callback received, we hold onto the object created for each - * uid and reuse it. + * uid and reuse it until the uid stays alive. * * Note that the lock used for accessing this object should not be used for anything else and we * should not be acquiring new locks or doing any heavy work while this lock is held since this @@ -800,6 +800,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Clock.systemUTC()); } + @VisibleForTesting + UidState getUidStateForTest(int uid) { + synchronized (mUidRulesFirstLock) { + return mUidState.get(uid); + } + } + static class Dependencies { final Context mContext; final NetworkStatsManager mNetworkStatsManager; @@ -1254,6 +1261,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override public void onUidGone(int uid, boolean disabled) { + synchronized (mUidStateCallbackInfos) { + mUidStateCallbackInfos.remove(uid); + } + // TODO: b/327058756 - Remove any pending UID_MSG_STATE_CHANGED on the handler. mUidEventHandler.obtainMessage(UID_MSG_GONE, uid, 0).sendToTarget(); } }; @@ -5915,7 +5926,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { void handleUidGone(int uid) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidGone"); try { - boolean updated; + final boolean updated; synchronized (mUidRulesFirstLock) { updated = removeUidStateUL(uid); } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index eed0eecb0a22..6857869e3776 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -1285,8 +1285,8 @@ public class ZenModeHelper { */ private static void updateZenDeviceEffects(ZenRule zenRule, @Nullable ZenDeviceEffects newEffects, boolean isFromApp, boolean updateBitmask) { + // Same as with ZenPolicy, supplying null effects means keeping the previous ones. if (newEffects == null) { - zenRule.zenDeviceEffects = null; return; } diff --git a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java index 5ad550722c93..5ebcca875d86 100644 --- a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java +++ b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java @@ -626,7 +626,7 @@ public class PersistentDataBlockService extends SystemService { // version. If so, we deactivate FRP and set the secret to the default value. if (isUpgradingFromPreVRelease()) { Slog.w(TAG, "Upgrading from Android 14 or lower, defaulting FRP secret"); - writeFrpMagicAndDefaultSecretLocked(); + writeFrpMagicAndDefaultSecret(); mFrpActive = false; return true; } @@ -726,7 +726,7 @@ public class PersistentDataBlockService extends SystemService { synchronized (mLock) { if (!hasFrpSecretMagic()) { Slog.i(TAG, "No FRP secret magic, system must have been upgraded."); - writeFrpMagicAndDefaultSecretLocked(); + writeFrpMagicAndDefaultSecret(); } } @@ -748,7 +748,7 @@ public class PersistentDataBlockService extends SystemService { } } - private void writeFrpMagicAndDefaultSecretLocked() { + private void writeFrpMagicAndDefaultSecret() { try (FileChannel channel = getBlockOutputChannelIgnoringFrp()) { synchronized (mLock) { Slog.i(TAG, "Writing default FRP secret"); diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index a1dac0456ff9..5bd8ca63c3ff 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -17,6 +17,8 @@ package com.android.server.pm; import static android.content.pm.Flags.disallowSdkLibsToBeApps; +import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK; +import static android.content.pm.PackageManager.APP_METADATA_SOURCE_INSTALLER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS; @@ -43,11 +45,11 @@ import static android.os.storage.StorageManager.FLAG_STORAGE_CE; import static android.os.storage.StorageManager.FLAG_STORAGE_DE; import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL; +import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.APP_METADATA_FILE_NAME; import static com.android.server.pm.DexOptHelper.useArtService; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet; import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; -import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_NAME; import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION; import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; @@ -701,7 +703,7 @@ final class InstallPackageHelper { pkgSetting.setUninstallReason(PackageManager.UNINSTALL_REASON_UNKNOWN, userId); pkgSetting.setFirstInstallTime(System.currentTimeMillis(), userId); // Clear any existing archive state. - mPm.mInstallerService.mPackageArchiver.clearArchiveState(packageName, userId); + mPm.mInstallerService.mPackageArchiver.clearArchiveState(pkgSetting, userId); mPm.mSettings.writePackageRestrictionsLPr(userId); mPm.mSettings.writeKernelMappingLPr(pkgSetting); installed = true; @@ -829,7 +831,8 @@ final class InstallPackageHelper { if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token); - if (request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED && doRestore) { + final boolean succeeded = request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED; + if (succeeded && doRestore) { // Pass responsibility to the Backup Manager. It will perform a // restore if appropriate, then pass responsibility back to the // Package Manager to run the post-install observer callbacks @@ -843,10 +846,27 @@ final class InstallPackageHelper { // need to be snapshotted or restored for the package. // // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL. - if (request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) { + if (succeeded && !doRestore && update) { doRestore = performRollbackManagerRestore(userId, token, request); } + if (succeeded && !request.hasPostInstallRunnable()) { + boolean hasNeverBeenRestored = + packageSetting != null && packageSetting.isPendingRestore(); + request.setPostInstallRunnable(() -> { + // Permissions should be restored on each user that has the app installed for the + // first time, unless it's an unarchive install for an archived app, in which case + // the permissions should be restored on each user that has the app updated. + int[] userIdsToRestorePermissions = hasNeverBeenRestored + ? request.getUpdateBroadcastUserIds() + : request.getFirstTimeBroadcastUserIds(); + for (int restorePermissionUserId : userIdsToRestorePermissions) { + mPm.restorePermissionsAndUpdateRolesForNewUserInstall(request.getName(), + restorePermissionUserId); + } + }); + } + if (doRestore) { if (packageSetting != null) { synchronized (mPm.mLock) { @@ -2207,10 +2227,16 @@ final class InstallPackageHelper { if (appMetadataFile.exists()) { ps.setAppMetadataFilePath(appMetadataFile.getAbsolutePath()); if (Flags.aslInApkAppMetadataSource()) { - ps.setAppMetadataSource(PackageManager.APP_METADATA_SOURCE_INSTALLER); + ps.setAppMetadataSource(APP_METADATA_SOURCE_INSTALLER); } } else { - ps.setAppMetadataFilePath(null); + if (Flags.aslInApkAppMetadataSource() + && parsedPackage.isAppMetadataFileInApk()) { + ps.setAppMetadataFilePath(appMetadataFile.getAbsolutePath()); + ps.setAppMetadataSource(APP_METADATA_SOURCE_APK); + } else { + ps.setAppMetadataFilePath(null); + } } } if (installRequest.getReturnCode() == PackageManager.INSTALL_SUCCEEDED) { @@ -2327,7 +2353,7 @@ final class InstallPackageHelper { installerPackageName); } // Clear any existing archive state. - mPm.mInstallerService.mPackageArchiver.clearArchiveState(pkgName, userId); + mPm.mInstallerService.mPackageArchiver.clearArchiveState(ps, userId); } else if (allUsers != null) { // The caller explicitly specified INSTALL_ALL_USERS flag. // Thus, updating the settings to install the app for all users. @@ -2351,7 +2377,7 @@ final class InstallPackageHelper { installerPackageName); } // Clear any existing archive state. - mPm.mInstallerService.mPackageArchiver.clearArchiveState(pkgName, + mPm.mInstallerService.mPackageArchiver.clearArchiveState(ps, currentUserId); } else { ps.setInstalled(false, currentUserId); @@ -2851,7 +2877,6 @@ final class InstallPackageHelper { mPm.notifyInstantAppPackageInstalled(request.getPkg().getPackageName(), request.getNewUsers()); - request.populateBroadcastUsers(); final int[] firstUserIds = request.getFirstTimeBroadcastUserIds(); if (request.getPkg().getStaticSharedLibraryName() == null) { @@ -2863,12 +2888,6 @@ final class InstallPackageHelper { mPm.mRequiredInstallerPackage, /* packageSender= */ mPm, launchedForRestore, killApp, update, archived); - // Work that needs to happen on first install within each user - for (int userId : firstUserIds) { - mPm.restorePermissionsAndUpdateRolesForNewUserInstall(packageName, - userId); - } - if (request.isAllNewUsers() && !update) { mPm.notifyPackageAdded(packageName, request.getAppId()); } else { diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java index 4fb0c220708f..43075a232a23 100644 --- a/services/core/java/com/android/server/pm/InstallRequest.java +++ b/services/core/java/com/android/server/pm/InstallRequest.java @@ -692,6 +692,14 @@ final class InstallRequest { } } + public void setPostInstallRunnable(Runnable runnable) { + mPostInstallRunnable = runnable; + } + + public boolean hasPostInstallRunnable() { + return mPostInstallRunnable != null; + } + public void runPostInstallRunnable() { if (mPostInstallRunnable != null) { mPostInstallRunnable.run(); @@ -753,6 +761,7 @@ final class InstallRequest { public void setNewUsers(int[] newUsers) { mNewUsers = newUsers; + populateBroadcastUsers(); } public void setOriginPackage(String originPackage) { @@ -829,10 +838,11 @@ final class InstallRequest { } /** - * Determine the set of users who are adding this package for the first time vs. those who are - * seeing an update. + * Determine the set of users who are adding this package for the first time (aka "new" users) + * vs. those who are seeing an update (aka "update" users). The lists can be calculated as soon + * as the "new" users are set. */ - public void populateBroadcastUsers() { + private void populateBroadcastUsers() { assertScanResultExists(); mFirstTimeBroadcastUserIds = EMPTY_INT_ARRAY; mFirstTimeBroadcastInstantUserIds = EMPTY_INT_ARRAY; diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index d8d8dd2e57a9..9b0fec2c757b 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -22,8 +22,8 @@ import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_IGNORED; import static android.app.AppOpsManager.OP_ARCHIVE_ICON_OVERLAY; import static android.app.AppOpsManager.OP_UNARCHIVAL_CONFIRMATION; -import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; -import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; +import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; +import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_MUTABLE; import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; @@ -2209,8 +2209,10 @@ public class LauncherAppsService extends SystemService { for (UserHandle user : users) { mPackageManagerInternal.forEachInstalledPackage(pkg -> { final String packageName = pkg.getPackageName(); - if (mPackageManagerInternal.getIncrementalStatesInfo(packageName, - Process.myUid(), user.getIdentifier()).isLoading()) { + final IncrementalStatesInfo info = + mPackageManagerInternal.getIncrementalStatesInfo(packageName, + Process.myUid(), user.getIdentifier()); + if (info != null && info.isLoading()) { mPackageManagerInternal.registerInstalledLoadingProgressCallback( packageName, new PackageLoadingProgressCallback(packageName, user), user.getIdentifier()); diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java index cdd52a47e433..ef8453dcee67 100644 --- a/services/core/java/com/android/server/pm/PackageArchiver.java +++ b/services/core/java/com/android/server/pm/PackageArchiver.java @@ -21,7 +21,7 @@ import static android.app.ActivityManager.START_CLASS_NOT_FOUND; import static android.app.ActivityManager.START_PERMISSION_DENIED; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_IGNORED; -import static android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; +import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; import static android.content.pm.ArchivedActivityInfo.bytesFromBitmap; import static android.content.pm.ArchivedActivityInfo.drawableToBitmap; import static android.content.pm.PackageInstaller.EXTRA_UNARCHIVE_STATUS; @@ -356,19 +356,34 @@ public class PackageArchiver { } void clearArchiveState(String packageName, int userId) { + final PackageSetting ps; synchronized (mPm.mLock) { - PackageSetting ps = mPm.mSettings.getPackageLPr(packageName); - if (ps != null) { - ps.setArchiveState(/* archiveState= */ null, userId); + ps = mPm.mSettings.getPackageLPr(packageName); + } + clearArchiveState(ps, userId); + } + + void clearArchiveState(PackageSetting ps, int userId) { + synchronized (mPm.mLock) { + if (ps == null || ps.getUserStateOrDefault(userId).getArchiveState() == null) { + // No archive states to clear + return; } + if (DEBUG) { + Slog.e(TAG, "Clearing archive states for " + ps.getPackageName()); + } + ps.setArchiveState(/* archiveState= */ null, userId); } - File iconsDir = getIconsDir(packageName, userId); + File iconsDir = getIconsDir(ps.getPackageName(), userId); if (!iconsDir.exists()) { + if (DEBUG) { + Slog.e(TAG, "Icons are already deleted at " + iconsDir.getAbsolutePath()); + } return; } // TODO(b/319238030) Move this into installd. if (!FileUtils.deleteContentsAndDir(iconsDir)) { - Slog.e(TAG, "Failed to clean up archive files for " + packageName); + Slog.e(TAG, "Failed to clean up archive files for " + ps.getPackageName()); } else { if (DEBUG) { Slog.e(TAG, "Deleted icons at " + iconsDir.getAbsolutePath()); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 5792d864a8ab..ba903789e759 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -358,7 +358,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { /** Default byte size limit for app metadata */ private static final long DEFAULT_APP_METADATA_BYTE_SIZE_LIMIT = 32000; - private static final int APP_METADATA_FILE_ACCESS_MODE = 0640; + static final int APP_METADATA_FILE_ACCESS_MODE = 0640; /** * Throws IllegalArgumentException if the {@link IntentSender} from an immutable @@ -964,7 +964,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private boolean isEmergencyInstallerEnabled(String packageName, Computer snapshot) { final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName); - if (ps == null || ps.getPkg() == null || !ps.isSystem()) { + if (ps == null || ps.getPkg() == null) { return false; } String emergencyInstaller = ps.getPkg().getEmergencyInstaller(); @@ -1782,8 +1782,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } private File getStagedAppMetadataFile() { - File file = new File(stageDir, APP_METADATA_FILE_NAME); - return file.exists() ? file : null; + return new File(stageDir, APP_METADATA_FILE_NAME); } private static boolean isAppMetadata(String name) { @@ -1799,7 +1798,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { assertCallerIsOwnerOrRoot(); synchronized (mLock) { assertPreparedAndNotCommittedOrDestroyedLocked("getAppMetadataFd"); - if (getStagedAppMetadataFile() == null) { + if (!getStagedAppMetadataFile().exists()) { return null; } try { @@ -1813,12 +1812,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void removeAppMetadata() { File file = getStagedAppMetadataFile(); - if (file != null) { + if (file.exists()) { file.delete(); } } - private static long getAppMetadataSizeLimit() { + static long getAppMetadataSizeLimit() { final long token = Binder.clearCallingIdentity(); try { return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE, @@ -2131,7 +2130,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } File appMetadataFile = getStagedAppMetadataFile(); - if (appMetadataFile != null) { + if (appMetadataFile.exists()) { long sizeLimit = getAppMetadataSizeLimit(); if (appMetadataFile.length() > sizeLimit) { appMetadataFile.delete(); @@ -3419,7 +3418,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final List<ApkLite> addedFiles = getAddedApkLitesLocked(); if (addedFiles.isEmpty() - && (removeSplitList.size() == 0 || getStagedAppMetadataFile() != null)) { + && (removeSplitList.size() == 0 || getStagedAppMetadataFile().exists())) { throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, TextUtils.formatSimple("Session: %d. No packages staged in %s", sessionId, stageDir.getAbsolutePath())); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index dadafd7f9438..69f790637d80 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -18,6 +18,8 @@ package com.android.server.pm; import static android.Manifest.permission.MANAGE_DEVICE_ADMINS; import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS; import static android.app.AppOpsManager.MODE_IGNORED; +import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK; +import static android.content.pm.PackageManager.APP_METADATA_SOURCE_UNKNOWN; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; @@ -596,7 +598,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService static final String RANDOM_DIR_PREFIX = "~~"; static final char RANDOM_CODEPATH_PREFIX = '-'; - static final String APP_METADATA_FILE_NAME = "app.metadata"; + public static final String APP_METADATA_FILE_NAME = "app.metadata"; + public static final String APP_METADATA_FILE_IN_APK_PATH = "assets/" + APP_METADATA_FILE_NAME; static final int DEFAULT_FILE_ACCESS_MODE = 0644; @@ -721,7 +724,6 @@ public class PackageManagerService implements PackageSender, TestUtilityService PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy; - @GuardedBy("mAvailableFeatures") private final ArrayMap<String, FeatureInfo> mAvailableFeatures; @Watched @@ -2983,13 +2985,11 @@ public class PackageManagerService implements PackageSender, TestUtilityService public boolean hasSystemFeature(String name, int version) { // allow instant applications - synchronized (mAvailableFeatures) { - final FeatureInfo feat = mAvailableFeatures.get(name); - if (feat == null) { - return false; - } else { - return feat.version >= version; - } + final FeatureInfo feat = mAvailableFeatures.get(name); + if (feat == null) { + return false; + } else { + return feat.version >= version; } } @@ -5230,15 +5230,30 @@ public class PackageManagerService implements PackageSender, TestUtilityService new PackageManager.NameNotFoundException(packageName)); } String filePath = ps.getAppMetadataFilePath(); - if (filePath != null) { - File file = new File(filePath); - try { - return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); - } catch (FileNotFoundException e) { + if (filePath == null) { + return null; + } + File file = new File(filePath); + if (Flags.aslInApkAppMetadataSource() && !file.exists() + && ps.getAppMetadataSource() == APP_METADATA_SOURCE_APK) { + String apkPath = ps.getPkg().getSplits().get(0).getPath(); + if (!PackageManagerServiceUtils.extractAppMetadataFromApk(apkPath, file)) { + if (file.exists()) { + file.delete(); + } + synchronized (mLock) { + PackageSetting pkgSetting = mSettings.getPackageLPr(packageName); + pkgSetting.setAppMetadataFilePath(null); + pkgSetting.setAppMetadataSource(APP_METADATA_SOURCE_UNKNOWN); + } return null; } } - return null; + try { + return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); + } catch (FileNotFoundException e) { + return null; + } } @android.annotation.EnforcePermission(android.Manifest.permission.GET_APP_METADATA) @@ -5335,10 +5350,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService public @NonNull ParceledListSlice<FeatureInfo> getSystemAvailableFeatures() { // allow instant applications ArrayList<FeatureInfo> res; - synchronized (mAvailableFeatures) { - res = new ArrayList<>(mAvailableFeatures.size() + 1); - res.addAll(mAvailableFeatures.values()); - } + res = new ArrayList<>(mAvailableFeatures.size() + 1); + res.addAll(mAvailableFeatures.values()); final FeatureInfo fi = new FeatureInfo(); fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version", FeatureInfo.GL_ES_VERSION_UNDEFINED); @@ -6542,9 +6555,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService mOverlayConfigSignaturePackage, mRecentsPackage); final ArrayMap<String, FeatureInfo> availableFeatures; - synchronized (mAvailableFeatures) { - availableFeatures = new ArrayMap<>(mAvailableFeatures); - } + availableFeatures = new ArrayMap<>(mAvailableFeatures); final ArraySet<String> protectedBroadcasts; synchronized (mProtectedBroadcasts) { protectedBroadcasts = new ArraySet<>(mProtectedBroadcasts); diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 0a3dfc08686a..189a138a191a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -27,6 +27,9 @@ import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME; import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME; import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH; import static com.android.server.LocalManagerRegistry.ManagerNotFoundException; +import static com.android.server.pm.PackageInstallerSession.APP_METADATA_FILE_ACCESS_MODE; +import static com.android.server.pm.PackageInstallerSession.getAppMetadataSizeLimit; +import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_IN_APK_PATH; import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION; import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION; import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING; @@ -142,6 +145,8 @@ import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.zip.GZIPInputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; /** * Class containing helper methods for the PackageManagerService. @@ -1559,6 +1564,35 @@ public class PackageManagerServiceUtils { return initiatingPackageName == null || SHELL_PACKAGE_NAME.equals(initiatingPackageName); } + /** + * Extract the app.metadata file from apk. + */ + public static boolean extractAppMetadataFromApk(String apkPath, File appMetadataFile) { + boolean found = false; + try (ZipInputStream zipInputStream = + new ZipInputStream(new FileInputStream(new File(apkPath)))) { + ZipEntry zipEntry = null; + while ((zipEntry = zipInputStream.getNextEntry()) != null) { + if (zipEntry.getName().equals(APP_METADATA_FILE_IN_APK_PATH)) { + found = true; + try (FileOutputStream out = new FileOutputStream(appMetadataFile)) { + FileUtils.copy(zipInputStream, out); + } + if (appMetadataFile.length() > getAppMetadataSizeLimit()) { + appMetadataFile.delete(); + return false; + } + Os.chmod(appMetadataFile.getAbsolutePath(), APP_METADATA_FILE_ACCESS_MODE); + break; + } + } + } catch (Exception e) { + Slog.e(TAG, e.getMessage()); + return false; + } + return found; + } + public static void linkFilesToOldDirs(@NonNull Installer installer, @NonNull String packageName, @NonNull File newPath, diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java index 5e8778d3e29c..9a7916a7b215 100644 --- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java +++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java @@ -53,7 +53,7 @@ import java.util.Map; * as install) led to the request. */ final class ReconcilePackageUtils { - private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE = Build.IS_DEBUGGABLE; + private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE = Build.IS_DEBUGGABLE || true; public static List<ReconciledPackage> reconcilePackages( List<InstallRequest> installRequests, diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java index 1c70af0a56ea..b18503d7d5cb 100644 --- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java +++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java @@ -596,7 +596,7 @@ public class PackageInfoUtils { ai.requiredDisplayCategory = a.getRequiredDisplayCategory(); ai.requireContentUriPermissionFromCaller = a.getRequireContentUriPermissionFromCaller(); ai.setKnownActivityEmbeddingCerts(a.getKnownActivityEmbeddingCerts()); - assignFieldsComponentInfoParsedMainComponent(ai, a, pkgSetting, userId); + assignFieldsComponentInfoParsedMainComponent(ai, a, pkgSetting, state, userId); return ai; } @@ -659,7 +659,7 @@ public class PackageInfoUtils { // Backwards compatibility, coerce to null if empty si.metaData = metaData.isEmpty() ? null : metaData; } - assignFieldsComponentInfoParsedMainComponent(si, s, pkgSetting, userId); + assignFieldsComponentInfoParsedMainComponent(si, s, pkgSetting, state, userId); return si; } @@ -710,7 +710,7 @@ public class PackageInfoUtils { pi.metaData = metaData.isEmpty() ? null : metaData; } pi.applicationInfo = applicationInfo; - assignFieldsComponentInfoParsedMainComponent(pi, p, pkgSetting, userId); + assignFieldsComponentInfoParsedMainComponent(pi, p, pkgSetting, state, userId); return pi; } @@ -903,8 +903,13 @@ public class PackageInfoUtils { private static void assignFieldsComponentInfoParsedMainComponent( @NonNull ComponentInfo info, @NonNull ParsedMainComponent component, - @NonNull PackageStateInternal pkgSetting, @UserIdInt int userId) { + @NonNull PackageStateInternal pkgSetting, @NonNull PackageUserStateInternal state, + @UserIdInt int userId) { assignFieldsComponentInfoParsedMainComponent(info, component); + // overwrite the enabled state with the current user state + info.enabled = PackageUserStateUtils.isEnabled(state, info.applicationInfo.enabled, + info.enabled, info.name, /* flags */ 0); + Pair<CharSequence, Integer> labelAndIcon = ParsedComponentStateUtils.getNonLocalizedLabelAndIcon(component, pkgSetting, userId); diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index f15646f634c2..984994170876 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -237,7 +237,7 @@ public final class PermissionPolicyService extends SystemService { mAppOpsCallback = new IAppOpsCallback.Stub() { public void opChanged(int op, int uid, @Nullable String packageName, String persistentDeviceId) { - if (Objects.equals(persistentDeviceId, + if (!Objects.equals(persistentDeviceId, VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT)) { return; } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 8781bf19565e..428fca082f75 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3504,8 +3504,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) { StatusBarManagerInternal statusbar = getStatusBarManagerInternal(); if (statusbar != null) { - statusbar.goToFullscreenFromSplit(); - logKeyboardSystemsEvent(event, KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION); + statusbar.moveFocusedTaskToFullscreen(event.getDisplayId()); + logKeyboardSystemsEvent(event, KeyboardLogEvent.MULTI_WINDOW_NAVIGATION); return true; } } diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java index b22e37bd579b..c8cb92b915da 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java @@ -167,6 +167,9 @@ public class BatterySaverStateMachine { /** Config flag to track if battery saver's sticky behaviour is disabled. */ private final boolean mBatterySaverStickyBehaviourDisabled; + /** Config flag to track if "Battery Saver turned off" notification is enabled. */ + private final boolean mBatterySaverTurnedOffNotificationEnabled; + /** * Whether or not to end sticky battery saver upon reaching a level specified by * {@link #mSettingBatterySaverStickyAutoDisableThreshold}. @@ -250,6 +253,8 @@ public class BatterySaverStateMachine { mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled); + mBatterySaverTurnedOffNotificationEnabled = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_batterySaverTurnedOffNotificationEnabled); mDynamicPowerSavingsDefaultDisableThreshold = mContext.getResources().getInteger( com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold); } @@ -858,6 +863,9 @@ public class BatterySaverStateMachine { @VisibleForTesting void triggerStickyDisabledNotification() { + if (!mBatterySaverTurnedOffNotificationEnabled) { + return; + } // The current lock is the PowerManager lock, which sits very low in the service lock // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock. runOnBgThread(() -> { @@ -997,6 +1005,8 @@ public class BatterySaverStateMachine { ipw.println(mSettingBatterySaverTriggerThreshold); ipw.print("mBatterySaverStickyBehaviourDisabled="); ipw.println(mBatterySaverStickyBehaviourDisabled); + ipw.print("mBatterySaverTurnedOffNotificationEnabled="); + ipw.println(mBatterySaverTurnedOffNotificationEnabled); ipw.print("mDynamicPowerSavingsDefaultDisableThreshold="); ipw.println(mDynamicPowerSavingsDefaultDisableThreshold); diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java index ab27ac10df76..8e3c6ac799b4 100644 --- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java +++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java @@ -1591,32 +1591,76 @@ public class BatteryStatsImpl extends BatteryStats { @Override public WakeLockStats getWakeLockStats() { final long realtimeMs = mClock.elapsedRealtime(); - final long realtimeUs = realtimeMs * 1000; List<WakeLockStats.WakeLock> uidWakeLockStats = new ArrayList<>(); + List<WakeLockStats.WakeLock> uidAggregatedWakeLockStats = new ArrayList<>(); for (int i = mUidStats.size() - 1; i >= 0; i--) { final Uid uid = mUidStats.valueAt(i); + + // Converts unaggregated wakelocks. final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats = uid.mWakelockStats.getMap(); for (int j = wakelockStats.size() - 1; j >= 0; j--) { final String name = wakelockStats.keyAt(j); final Uid.Wakelock wakelock = (Uid.Wakelock) wakelockStats.valueAt(j); - final DualTimer timer = wakelock.mTimerPartial; - if (timer != null) { - final long totalTimeLockHeldMs = - timer.getTotalTimeLocked(realtimeUs, STATS_SINCE_CHARGED) / 1000; - if (totalTimeLockHeldMs != 0) { - uidWakeLockStats.add( - new WakeLockStats.WakeLock(uid.getUid(), name, - timer.getCountLocked(STATS_SINCE_CHARGED), - totalTimeLockHeldMs, - timer.isRunningLocked() - ? timer.getCurrentDurationMsLocked(realtimeMs) - : 0)); - } + final WakeLockStats.WakeLock wakeLockItem = + createWakeLock(uid, name, /* isAggregated= */ false, wakelock.mTimerPartial, + realtimeMs); + if (wakeLockItem != null) { + uidWakeLockStats.add(wakeLockItem); } } + + // Converts aggregated wakelocks. + final WakeLockStats.WakeLock aggregatedWakeLockItem = + createWakeLock( + uid, + WakeLockStats.WakeLock.NAME_AGGREGATED, + /* isAggregated= */ true, + uid.mAggregatedPartialWakelockTimer, + realtimeMs); + if (aggregatedWakeLockItem != null) { + uidAggregatedWakeLockStats.add(aggregatedWakeLockItem); + } + } + return new WakeLockStats(uidWakeLockStats, uidAggregatedWakeLockStats); + } + + // Returns a valid {@code WakeLockStats.WakeLock} or null. + private WakeLockStats.WakeLock createWakeLock( + Uid uid, String name, boolean isAggregated, DualTimer timer, final long realtimeMs) { + if (timer == null) { + return null; + } + // Uses the primary timer for total wakelock data and used the sub timer for background + // wakelock data. + final WakeLockStats.WakeLockData totalWakeLockData = createWakeLockData(timer, realtimeMs); + final WakeLockStats.WakeLockData backgroundWakeLockData = + createWakeLockData(timer.getSubTimer(), realtimeMs); + + return WakeLockStats.WakeLock.isDataValid(totalWakeLockData, backgroundWakeLockData) + ? new WakeLockStats.WakeLock( + uid.getUid(), + name, + isAggregated, + totalWakeLockData, + backgroundWakeLockData) : null; + } + + @NonNull + private WakeLockStats.WakeLockData createWakeLockData( + DurationTimer timer, final long realtimeMs) { + if (timer == null) { + return WakeLockStats.WakeLockData.EMPTY; + } + final long totalTimeLockHeldMs = + timer.getTotalTimeLocked(realtimeMs * 1000, STATS_SINCE_CHARGED) / 1000; + if (totalTimeLockHeldMs == 0) { + return WakeLockStats.WakeLockData.EMPTY; } - return new WakeLockStats(uidWakeLockStats); + return new WakeLockStats.WakeLockData( + timer.getCountLocked(STATS_SINCE_CHARGED), + totalTimeLockHeldMs, + timer.isRunningLocked() ? timer.getCurrentDurationMsLocked(realtimeMs) : 0); } @Override diff --git a/services/core/java/com/android/server/power/stats/PowerStatsSpan.java b/services/core/java/com/android/server/power/stats/PowerStatsSpan.java index 3b260ca0c3b9..4df919dffbe5 100644 --- a/services/core/java/com/android/server/power/stats/PowerStatsSpan.java +++ b/services/core/java/com/android/server/power/stats/PowerStatsSpan.java @@ -57,7 +57,7 @@ public class PowerStatsSpan { * {@link #isCompatibleXmlFormat} to return true for all legacy versions * that are compatible with the new one. */ - private static final int VERSION = 1; + private static final int VERSION = 2; private static final String XML_TAG_METADATA = "metadata"; private static final String XML_ATTR_ID = "id"; diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java index bb5a697114d3..7ddb61e5ca52 100644 --- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java +++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java @@ -68,12 +68,14 @@ final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecogn private final ComponentName mComponentName; RemoteSpeechRecognitionService( - Context context, ComponentName serviceName, int userId, int callingUid) { + Context context, + ComponentName serviceName, + int userId, + int callingUid, + boolean isPrivileged) { super(context, new Intent(RecognitionService.SERVICE_INTERFACE).setComponent(serviceName), - Context.BIND_AUTO_CREATE - | Context.BIND_FOREGROUND_SERVICE - | Context.BIND_INCLUDE_CAPABILITIES, + getBindingFlags(isPrivileged), userId, IRecognitionService.Stub::asInterface); @@ -85,6 +87,14 @@ final class RemoteSpeechRecognitionService extends ServiceConnector.Impl<IRecogn } } + private static int getBindingFlags(boolean isPrivileged) { + int bindingFlags = Context.BIND_AUTO_CREATE; + if (isPrivileged) { + bindingFlags |= Context.BIND_INCLUDE_CAPABILITIES | Context.BIND_FOREGROUND_SERVICE; + } + return bindingFlags; + } + ComponentName getServiceComponentName() { return mComponentName; } diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java index 8e9c889c8ef3..808504f50acc 100644 --- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java +++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java @@ -23,6 +23,7 @@ import android.app.AppGlobals; import android.content.AttributionSource; import android.content.ComponentName; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; @@ -31,6 +32,7 @@ import android.os.IBinder; import android.os.Process; import android.os.RemoteException; import android.permission.PermissionManager; +import android.provider.Settings; import android.speech.IModelDownloadListener; import android.speech.IRecognitionListener; import android.speech.IRecognitionService; @@ -311,9 +313,22 @@ final class SpeechRecognitionManagerServiceImpl extends return null; } + final boolean isPrivileged; + if (serviceComponent == null) { + isPrivileged = false; + } else { + // Only certain privileged recognition service can obtain process capabilities + // from persistent process to hold while-in-use permission in the background. + isPrivileged = checkPrivilege(serviceComponent); + } + RemoteSpeechRecognitionService service = new RemoteSpeechRecognitionService( - getContext(), serviceComponent, getUserId(), callingUid); + getContext(), + serviceComponent, + getUserId(), + callingUid, + isPrivileged); Set<RemoteSpeechRecognitionService> valuesByCaller = mRemoteServicesByUid.computeIfAbsent(callingUid, key -> new HashSet<>()); @@ -328,6 +343,53 @@ final class SpeechRecognitionManagerServiceImpl extends } } + /** + * Checks if the given service component should have privileged binding flags when created. Only + * a service component that matches with any of the following condition would be granted: + * + * <ul> + * <li>A default recognition service component.</li> + * <li>An on-device recognition service component.</li> + * <li>A pre-installed recognition service component.</li> + * </ul> + */ + @GuardedBy("mLock") + private boolean checkPrivilege(@NonNull ComponentName serviceComponent) { + final ComponentName defaultComponent = getDefaultRecognitionServiceComponent(); + final ComponentName onDeviceComponent = getOnDeviceComponentNameLocked(); + final boolean preinstalled = isPreinstalledApp(serviceComponent); + return serviceComponent.equals(defaultComponent) + || serviceComponent.equals(onDeviceComponent) + || preinstalled; + } + + private boolean isPreinstalledApp(@NonNull ComponentName serviceComponent) { + PackageManager pm = getContext().getPackageManager(); + if (pm == null) { + return false; + } + + try { + ApplicationInfo info = pm.getApplicationInfoAsUser(serviceComponent.getPackageName(), + PackageManager.MATCH_SYSTEM_ONLY, getUserId()); + return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } catch (PackageManager.NameNotFoundException e) { + return false; + } + } + + @Nullable + private ComponentName getDefaultRecognitionServiceComponent() { + String componentName = Settings.Secure.getStringForUser( + getContext().getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, + getUserId()); + if (componentName == null) { + return null; + } + return ComponentName.unflattenFromString(componentName); + } + private boolean componentMapsToRecognitionService(@NonNull ComponentName serviceComponent) { List<ResolveInfo> resolveInfos; diff --git a/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java b/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java index b0dcf95b3f5d..881583ad8c91 100644 --- a/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java +++ b/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java @@ -282,10 +282,7 @@ class AggregatedMobileDataStatsPuller { Slog.d(TAG, "pullDataBytesTransferLocked() done. results count " + pulledData.size()); } - if (!pulledData.isEmpty()) { - return StatsManager.PULL_SUCCESS; - } - return StatsManager.PULL_SKIP; + return StatsManager.PULL_SUCCESS; } private static boolean isEmpty(NetworkStats stats) { diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index 3c6baa873eca..14e0ce1704c8 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -224,9 +224,11 @@ public interface StatusBarManagerInternal { void showRearDisplayDialog(int currentBaseState); /** - * Called when requested to go to fullscreen from the active split app. + * Called when requested to go to fullscreen from the focused app. + * + * @param displayId of the current display. */ - void goToFullscreenFromSplit(); + void moveFocusedTaskToFullscreen(int displayId); /** * Enters stage split from a current running app. diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 14c38bde6621..0b48a75298a4 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -810,11 +810,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } @Override - public void goToFullscreenFromSplit() { + public void moveFocusedTaskToFullscreen(int displayId) { IStatusBar bar = mBar; if (bar != null) { try { - bar.goToFullscreenFromSplit(); + bar.moveFocusedTaskToFullscreen(displayId); } catch (RemoteException ex) { } } } diff --git a/services/core/java/com/android/server/utils/AnrTimer.java b/services/core/java/com/android/server/utils/AnrTimer.java index 743005a2d844..b7d8cfce34ed 100644 --- a/services/core/java/com/android/server/utils/AnrTimer.java +++ b/services/core/java/com/android/server/utils/AnrTimer.java @@ -767,7 +767,7 @@ public class AnrTimer<V> implements AutoCloseable { * Return true if the native timers are supported. Native timers are supported if the method * nativeAnrTimerSupported() can be executed and it returns true. */ - private static boolean nativeTimersSupported() { + public static boolean nativeTimersSupported() { try { return nativeAnrTimerSupported(); } catch (java.lang.UnsatisfiedLinkError e) { diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java index 17f5e9585c22..7206c0377bf7 100644 --- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java +++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java @@ -164,7 +164,6 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { registerCarrierPrivilegesCallbacks(); } - // TODO(b/221306368): Refactor with the new onCarrierServiceChange in the new CPCallback private void registerCarrierPrivilegesCallbacks() { final HandlerExecutor executor = new HandlerExecutor(mHandler); final int modemCount = mTelephonyManager.getActiveModemCount(); diff --git a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java index 37f38252698e..601c7f450d4f 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperCropper.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperCropper.java @@ -357,15 +357,30 @@ public class WallpaperCropper { * Given some suggested crops, find cropHints for all orientations of the default display. */ SparseArray<Rect> getDefaultCrops(SparseArray<Rect> suggestedCrops, Point bitmapSize) { - SparseArray<Rect> result = new SparseArray<>(); - // add missing cropHints for all orientation of the default display + SparseArray<Point> defaultDisplaySizes = mWallpaperDisplayHelper.getDefaultDisplaySizes(); boolean rtl = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL; + + // adjust existing entries for the default display + SparseArray<Rect> adjustedSuggestedCrops = new SparseArray<>(); + for (int i = 0; i < defaultDisplaySizes.size(); i++) { + int orientation = defaultDisplaySizes.keyAt(i); + Point displaySize = defaultDisplaySizes.valueAt(i); + Rect suggestedCrop = suggestedCrops.get(orientation); + if (suggestedCrop != null) { + adjustedSuggestedCrops.put(orientation, + getCrop(displaySize, bitmapSize, suggestedCrops, rtl)); + } + } + + // add missing cropHints for all orientation of the default display + SparseArray<Rect> result = adjustedSuggestedCrops.clone(); for (int i = 0; i < defaultDisplaySizes.size(); i++) { int orientation = defaultDisplaySizes.keyAt(i); + if (result.contains(orientation)) continue; Point displaySize = defaultDisplaySizes.valueAt(i); - Rect newCrop = getCrop(displaySize, bitmapSize, suggestedCrops, rtl); + Rect newCrop = getCrop(displaySize, bitmapSize, adjustedSuggestedCrops, rtl); result.put(orientation, newCrop); } return result; diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java index 5f6ffd988c84..8742ab1dd95b 100644 --- a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java +++ b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java @@ -21,8 +21,8 @@ import static android.provider.DeviceConfig.NAMESPACE_WEARABLE_SENSING; import android.Manifest; import android.annotation.NonNull; import android.annotation.UserIdInt; +import android.app.ActivityOptions; import android.app.BroadcastOptions; -import android.app.ComponentOptions; import android.app.PendingIntent; import android.app.ambientcontext.AmbientContextEvent; import android.app.wearable.IWearableSensingManager; @@ -353,7 +353,7 @@ public class WearableSensingManagerService extends dataRequest); BroadcastOptions options = BroadcastOptions.makeBasic(); options.setPendingIntentBackgroundActivityStartMode( - ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED); + ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED); mDataRequestRateLimiter.noteEvent( userId, RATE_LIMITER_PACKAGE_NAME, RATE_LIMITER_TAG); final long previousCallingIdentity = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 44a0547a6828..d08e272d76dd 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -304,9 +304,9 @@ final class AccessibilityController { Surface forceShowMagnifierSurface(int displayId) { final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId); if (displayMagnifier != null) { - displayMagnifier.mMagnifedViewport.mWindow.setAlpha(DisplayMagnifier.MagnifiedViewport + displayMagnifier.mMagnifiedViewport.mWindow.setAlpha(DisplayMagnifier.MagnifiedViewport .ViewportWindow.AnimationController.MAX_ALPHA); - return displayMagnifier.mMagnifedViewport.mWindow.mSurface; + return displayMagnifier.mMagnifiedViewport.mWindow.mSurface; } return null; } @@ -463,6 +463,10 @@ final class AccessibilityController { } void drawMagnifiedRegionBorderIfNeeded(int displayId) { + if (Flags.magnificationAlwaysDrawFullscreenBorder()) { + return; + } + if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) { mAccessibilityTracing.logTrace( TAG + ".drawMagnifiedRegionBorderIfNeeded", @@ -614,7 +618,7 @@ final class AccessibilityController { private final Context mDisplayContext; private final WindowManagerService mService; - private final MagnifiedViewport mMagnifedViewport; + private final MagnifiedViewport mMagnifiedViewport; private final Handler mHandler; private final DisplayContent mDisplayContent; private final Display mDisplay; @@ -649,7 +653,8 @@ final class AccessibilityController { mDisplayContent = displayContent; mDisplay = display; mHandler = new MyHandler(mService.mH.getLooper()); - mMagnifedViewport = new MagnifiedViewport(); + mMagnifiedViewport = Flags.magnificationAlwaysDrawFullscreenBorder() + ? null : new MagnifiedViewport(); mAccessibilityTracing = AccessibilityController.getAccessibilityControllerInternal(mService); mLongAnimationDuration = mDisplayContext.getResources().getInteger( @@ -692,7 +697,9 @@ final class AccessibilityController { mMagnificationSpec.clear(); } - mMagnifedViewport.setShowMagnifiedBorderIfNeeded(); + if (!Flags.magnificationAlwaysDrawFullscreenBorder()) { + mMagnifiedViewport.setShowMagnifiedBorderIfNeeded(); + } } void setFullscreenMagnificationActivated(boolean activated) { @@ -701,8 +708,10 @@ final class AccessibilityController { FLAGS_MAGNIFICATION_CALLBACK, "activated=" + activated); } mIsFullscreenMagnificationActivated = activated; - mMagnifedViewport.setMagnifiedRegionBorderShown(activated, true); - mMagnifedViewport.showMagnificationBoundsIfNeeded(); + if (!Flags.magnificationAlwaysDrawFullscreenBorder()) { + mMagnifiedViewport.setMagnifiedRegionBorderShown(activated, true); + mMagnifiedViewport.showMagnificationBoundsIfNeeded(); + } } boolean isFullscreenMagnificationActivated() { @@ -737,7 +746,9 @@ final class AccessibilityController { } recomputeBounds(); - mMagnifedViewport.onDisplaySizeChanged(); + if (!Flags.magnificationAlwaysDrawFullscreenBorder()) { + mMagnifiedViewport.onDisplaySizeChanged(); + } mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED); } @@ -901,7 +912,10 @@ final class AccessibilityController { if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) { mAccessibilityTracing.logTrace(LOG_TAG + ".destroy", FLAGS_MAGNIFICATION_CALLBACK); } - mMagnifedViewport.destroyWindow(); + + if (!Flags.magnificationAlwaysDrawFullscreenBorder()) { + mMagnifiedViewport.destroyWindow(); + } } void drawMagnifiedRegionBorderIfNeeded() { @@ -909,7 +923,10 @@ final class AccessibilityController { mAccessibilityTracing.logTrace(LOG_TAG + ".drawMagnifiedRegionBorderIfNeeded", FLAGS_MAGNIFICATION_CALLBACK); } - mMagnifedViewport.drawWindowIfNeeded(); + + if (!Flags.magnificationAlwaysDrawFullscreenBorder()) { + mMagnifiedViewport.drawWindowIfNeeded(); + } } void recomputeBounds() { @@ -1006,14 +1023,16 @@ final class AccessibilityController { } visibleWindows.clear(); - mMagnifedViewport.intersectWithDrawBorderInset(screenWidth, screenHeight); - + if (!Flags.magnificationAlwaysDrawFullscreenBorder()) { + mMagnifiedViewport.intersectWithDrawBorderInset(screenWidth, screenHeight); + } final boolean magnifiedChanged = !mOldMagnificationRegion.equals(mMagnificationRegion); if (magnifiedChanged) { - mMagnifedViewport.updateBorderDrawingStatus(screenWidth, screenHeight); - + if (!Flags.magnificationAlwaysDrawFullscreenBorder()) { + mMagnifiedViewport.updateBorderDrawingStatus(screenWidth, screenHeight); + } mOldMagnificationRegion.set(mMagnificationRegion); final SomeArgs args = SomeArgs.obtain(); args.arg1 = Region.obtain(mMagnificationRegion); @@ -1070,7 +1089,9 @@ final class AccessibilityController { } void dump(PrintWriter pw, String prefix) { - mMagnifedViewport.dump(pw, prefix); + if (!Flags.magnificationAlwaysDrawFullscreenBorder()) { + mMagnifiedViewport.dump(pw, prefix); + } } private final class MagnifiedViewport { @@ -1079,7 +1100,7 @@ final class AccessibilityController { private final int mHalfBorderWidth; private final int mDrawBorderInset; - private final ViewportWindow mWindow; + @Nullable private final ViewportWindow mWindow; private boolean mFullRedrawNeeded; @@ -1138,9 +1159,9 @@ final class AccessibilityController { void onDisplaySizeChanged() { // If fullscreen magnification is activated, hide the border immediately so // the user does not see strange artifacts during display size changed caused by - // rotation or folding/unfolding the device. In the rotation case, the screenshot - // used for rotation already has the border. After the rotation is complete - // we will show the border. + // rotation or folding/unfolding the device. In the rotation case, the + // screenshot used for rotation already has the border. After the rotation is + // completed we will show the border. if (isFullscreenMagnificationActivated()) { setMagnifiedRegionBorderShown(false, false); final long delay = (long) (mLongAnimationDuration @@ -1173,6 +1194,8 @@ final class AccessibilityController { mWindow.dump(pw, prefix); } + // TODO(291891390): Remove this class when we clean up the flag + // magnificationAlwaysDrawFullscreenBorder private final class ViewportWindow implements Runnable { private static final String SURFACE_TITLE = "Magnification Overlay"; @@ -1467,6 +1490,9 @@ final class AccessibilityController { public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1; public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3; public static final int MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED = 4; + + // TODO(291891390): Remove this field when we clean up the flag + // magnificationAlwaysDrawFullscreenBorder public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5; public static final int MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED = 6; @@ -1495,7 +1521,9 @@ final class AccessibilityController { case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : { synchronized (mService.mGlobalLock) { if (isFullscreenMagnificationActivated()) { - mMagnifedViewport.setMagnifiedRegionBorderShown(true, true); + if (!Flags.magnificationAlwaysDrawFullscreenBorder()) { + mMagnifiedViewport.setMagnifiedRegionBorderShown(true, true); + } mService.scheduleAnimationLocked(); } } diff --git a/services/core/java/com/android/server/wm/ActivityAssistInfo.java b/services/core/java/com/android/server/wm/ActivityAssistInfo.java index 3b91780431cb..2dc00460eeb9 100644 --- a/services/core/java/com/android/server/wm/ActivityAssistInfo.java +++ b/services/core/java/com/android/server/wm/ActivityAssistInfo.java @@ -30,12 +30,14 @@ public class ActivityAssistInfo { private final IBinder mAssistToken; private final int mTaskId; private final ComponentName mComponentName; + private final int mUserId; public ActivityAssistInfo(ActivityRecord activityRecord) { this.mActivityToken = activityRecord.token; this.mAssistToken = activityRecord.assistToken; this.mTaskId = activityRecord.getTask().mTaskId; this.mComponentName = activityRecord.mActivityComponent; + this.mUserId = activityRecord.mUserId; } /** @hide */ @@ -57,4 +59,9 @@ public class ActivityAssistInfo { public ComponentName getComponentName() { return mComponentName; } + + /** @hide */ + public int getUserId() { + return mUserId; + } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index bc6f93fd64ac..90cff3950047 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -353,6 +353,7 @@ import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.TransitionOldType; import android.view.animation.Animation; +import android.window.ActivityWindowInfo; import android.window.ITaskFragmentOrganizer; import android.window.RemoteTransition; import android.window.SizeConfigurationBuckets; @@ -519,6 +520,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private int mLastReportedDisplayId; boolean mLastReportedMultiWindowMode; boolean mLastReportedPictureInPictureMode; + private final ActivityWindowInfo mLastReportedActivityWindowInfo = new ActivityWindowInfo(); ActivityRecord resultTo; // who started this entry, so will get our reply final String resultWho; // additional identifier for use by resultTo. final int requestCode; // code given by requester (resultTo) @@ -958,6 +960,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ private final Configuration mTmpConfig = new Configuration(); private final Rect mTmpBounds = new Rect(); + private final ActivityWindowInfo mTmpActivityWindowInfo = new ActivityWindowInfo(); // Token for targeting this activity for assist purposes. final Binder assistToken = new Binder(); @@ -1096,6 +1099,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.println(prefix + "mLastReportedConfigurations:"); mLastReportedConfiguration.dump(pw, prefix + " "); + if (Flags.activityWindowInfoFlag()) { + pw.print(prefix); + pw.print("mLastReportedActivityWindowInfo="); + pw.println(mLastReportedActivityWindowInfo); + } + pw.print(prefix); pw.print("CurrentConfiguration="); pw.println(getConfiguration()); if (!getRequestedOverrideConfiguration().equals(EMPTY)) { pw.println(prefix + "RequestedOverrideConfiguration=" @@ -1447,7 +1456,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mSizeConfigurations = sizeConfigurations; } - private void scheduleActivityMovedToDisplay(int displayId, Configuration config) { + private void scheduleActivityMovedToDisplay(int displayId, @NonNull Configuration config, + @NonNull ActivityWindowInfo activityWindowInfo) { if (!attachedToProcess()) { ProtoLog.w(WM_DEBUG_SWITCH, "Can't report activity moved " + "to display - client not running, activityRecord=%s, displayId=%d", @@ -1460,7 +1470,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A config); mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(), - MoveToDisplayItem.obtain(token, displayId, config)); + MoveToDisplayItem.obtain(token, displayId, config, activityWindowInfo)); } catch (RemoteException e) { // If process died, whatever. } @@ -3150,6 +3160,30 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + /** + * This is different from {@link #isEmbedded()}. + * {@link #isEmbedded()} is {@code true} when any of the parent {@link TaskFragment} is created + * by a {@link android.window.TaskFragmentOrganizer}, while this method is {@code true} when + * the parent {@link TaskFragment} is embedded and has bounds override that does not fill the + * leaf {@link Task}. + */ + boolean isEmbeddedInHostContainer() { + final TaskFragment taskFragment = getOrganizedTaskFragment(); + return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride(); + } + + @NonNull + ActivityWindowInfo getActivityWindowInfo() { + if (!Flags.activityWindowInfoFlag() || !isAttached()) { + return mTmpActivityWindowInfo; + } + mTmpActivityWindowInfo.set( + isEmbeddedInHostContainer(), + getTask().getBounds(), + getTaskFragment().getBounds()); + return mTmpActivityWindowInfo; + } + @Override @Nullable TaskDisplayArea getDisplayArea() { @@ -8213,6 +8247,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mLastReportedConfiguration.setConfiguration(global, override); } + void setLastReportedActivityWindowInfo(@NonNull ActivityWindowInfo activityWindowInfo) { + if (Flags.activityWindowInfoFlag()) { + mLastReportedActivityWindowInfo.set(activityWindowInfo); + } + } + @Nullable CompatDisplayInsets getCompatDisplayInsets() { if (mLetterboxUiController.hasInheritedLetterboxBehavior()) { @@ -9760,8 +9800,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Update last reported values. final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration(); + final ActivityWindowInfo newActivityWindowInfo = getActivityWindowInfo(); setLastReportedConfiguration(getProcessGlobalConfiguration(), newMergedOverrideConfig); + setLastReportedActivityWindowInfo(newActivityWindowInfo); if (mState == INITIALIZING) { // No need to relaunch or schedule new config for activity that hasn't been launched @@ -9778,7 +9820,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // There are no significant differences, so we won't relaunch but should still deliver // the new configuration to the client process. if (displayChanged) { - scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig); + scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig, + newActivityWindowInfo); } else { scheduleConfigurationChanged(newMergedOverrideConfig); } @@ -9845,7 +9888,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // changes is always sent to all processes when they happen so it can just use whatever // system level configuration it last got. if (displayChanged) { - scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig); + scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig, + newActivityWindowInfo); } else { scheduleConfigurationChanged(newMergedOverrideConfig); } @@ -10020,7 +10064,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pendingResults, pendingNewIntents, configChangeFlags, new MergedConfiguration(getProcessGlobalConfiguration(), getMergedOverrideConfiguration()), - preserveWindow); + preserveWindow, getActivityWindowInfo()); final ActivityLifecycleItem lifecycleItem; if (andResume) { lifecycleItem = ResumeActivityItem.obtain(token, isTransitionForward(), diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 066d26222fbd..c137c54949e9 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1548,6 +1548,8 @@ class ActivityStarter { result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor, startFlags, options, inTask, inTaskFragment, balVerdict, intentGrants, realCallingUid); + } catch (Exception ex) { + Slog.e(TAG, "Exception on startActivityInner", ex); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); startedActivityRootTask = handleStartResult(r, options, result, newTransition, diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 4a5b2211800c..c0881180af94 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -822,4 +822,7 @@ public abstract class ActivityTaskManagerInternal { */ public abstract void unregisterCompatScaleProvider( @CompatScaleProvider.CompatScaleModeOrderId int id); + + /** Returns whether assist data is allowed. */ + public abstract boolean isAssistDataAllowed(); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 24c8ebbfc2f7..218b7512b861 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -2505,6 +2505,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId, "getRecentTasks"); final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(), callingUid); + if (!mAmInternal.isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) { + Slog.i(TAG, "User " + userId + " is locked. Cannot load recents"); + return ParceledListSlice.emptyList(); + } + mRecentTasks.loadRecentTasksIfNeeded(userId); synchronized (mGlobalLock) { return mRecentTasks.getRecentTasks(maxNum, flags, allowed, userId, callingUid); } @@ -6018,6 +6023,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public int startActivityWithScreenshot(@NonNull Intent intent, @NonNull String callingPackage, int callingUid, int callingPid, @Nullable IBinder resultTo, @Nullable Bundle options, int userId) { + userId = getActivityStartController().checkTargetUser(userId, + false /* validateIncomingUser */, Binder.getCallingPid(), + Binder.getCallingUid(), "startActivityWithScreenshot"); + return getActivityStartController() .obtainStarter(intent, "startActivityWithScreenshot") .setCallingUid(callingUid) @@ -7056,11 +7065,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public void loadRecentTasksForUser(int userId) { - synchronized (mGlobalLock) { - mRecentTasks.loadUserRecentsLocked(userId); - // TODO renaming the methods(?) - mPackageConfigPersister.loadUserPackages(userId); - } + // This runs on android.fg thread when the user is unlocking. + mRecentTasks.loadRecentTasksIfNeeded(userId); + mPackageConfigPersister.loadUserPackages(userId); } @Override @@ -7344,6 +7351,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @CompatScaleProvider.CompatScaleModeOrderId int id) { ActivityTaskManagerService.this.unregisterCompatScaleProvider(id); } + + @Override + public boolean isAssistDataAllowed() { + return ActivityTaskManagerService.this.isAssistDataAllowed(); + } } static boolean isPip2ExperimentEnabled() { diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 09f5eda5b571..aefa777a1db7 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -138,6 +138,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import android.view.Display; +import android.window.ActivityWindowInfo; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; @@ -909,6 +910,9 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { final Configuration overrideConfig = r.getMergedOverrideConfiguration(); r.setLastReportedConfiguration(procConfig, overrideConfig); + final ActivityWindowInfo activityWindowInfo = r.getActivityWindowInfo(); + r.setLastReportedActivityWindowInfo(activityWindowInfo); + logIfTransactionTooLarge(r.intent, r.getSavedState()); final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment(); @@ -931,7 +935,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { results, newIntents, r.takeSceneTransitionInfo(), isTransitionForward, proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController, r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken, - r.initialCallerInfoAccessToken); + r.initialCallerInfoAccessToken, activityWindowInfo); // Set desired final state. final ActivityLifecycleItem lifecycleItem; @@ -1889,7 +1893,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { // Check that we aren't reparenting to the same root task that the task is already in if (prevRootTask != null && prevRootTask.mTaskId == rootTaskId) { Slog.w(TAG, "Can not reparent to same root task, task=" + task - + " already in rootTaskId=" + rootTaskId); + + " already in rootTaskId=" + rootTaskId + " by " + Debug.getCallers(8)); return prevRootTask; } diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 939cf1ae471b..1a63f14e1b8c 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -137,7 +137,6 @@ import android.view.animation.TranslateAnimation; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.TransitionAnimation; -import com.android.internal.protolog.ProtoLogImpl; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.DumpUtils.Dump; import com.android.internal.util.function.pooled.PooledLambda; @@ -248,7 +247,7 @@ public class AppTransition implements Dump { mHandler = new Handler(service.mH.getLooper()); mDisplayContent = displayContent; mTransitionAnimation = new TransitionAnimation( - context, ProtoLogImpl.isEnabled(WM_DEBUG_ANIM), TAG); + context, ProtoLog.isEnabled(WM_DEBUG_ANIM), TAG); mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false); diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java index fdae53f59ad4..4e28384c20be 100644 --- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java +++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java @@ -21,7 +21,7 @@ import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_DENIED; import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED; -import static android.app.ComponentOptions.BackgroundActivityStartMode; +import static android.app.ActivityOptions.BackgroundActivityStartMode; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE; diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java index 1dc9493eddc6..925a0776bf1e 100644 --- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java @@ -16,8 +16,6 @@ package com.android.server.wm; -import static android.util.DisplayMetrics.DENSITY_DEFAULT; - import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -29,8 +27,7 @@ import android.os.SystemProperties; import android.util.Slog; import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; -import com.android.wm.shell.Flags; - +import com.android.window.flags.Flags; /** * The class that defines default launch params for tasks in desktop mode */ @@ -40,16 +37,11 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { TAG_WITH_CLASS_NAME ? "DesktopModeLaunchParamsModifier" : TAG_ATM; private static final boolean DEBUG = false; - // Desktop mode feature flags. - private static final boolean ENABLE_DESKTOP_WINDOWING = Flags.enableDesktopWindowing(); private static final boolean DESKTOP_MODE_PROTO2_SUPPORTED = SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false); - // Override default freeform task width when desktop mode is enabled. In dips. - private static final int DESKTOP_MODE_DEFAULT_WIDTH_DP = SystemProperties.getInt( - "persist.wm.debug.desktop_mode.default_width", 840); - // Override default freeform task height when desktop mode is enabled. In dips. - private static final int DESKTOP_MODE_DEFAULT_HEIGHT_DP = SystemProperties.getInt( - "persist.wm.debug.desktop_mode.default_height", 630); + public static final float DESKTOP_MODE_INITIAL_BOUNDS_SCALE = + SystemProperties + .getInt("persist.wm.debug.desktop_mode_initial_bounds_scale", 75) / 100f; private StringBuilder mLogBuilder; @@ -73,6 +65,11 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { LaunchParamsController.LaunchParams currentParams, LaunchParamsController.LaunchParams outParams) { + if (!isDesktopModeEnabled()) { + appendLog("desktop mode is not enabled, continuing"); + return RESULT_CONTINUE; + } + if (task == null) { appendLog("task null, skipping"); return RESULT_SKIP; @@ -93,7 +90,7 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { // previous windowing mode to be restored even if the desktop mode state has changed. // Let task launches inherit the windowing mode from the source task if available, which // should have the desired windowing mode set by WM Shell. See b/286929122. - if (isDesktopModeSupported() && source != null && source.getTask() != null) { + if (isDesktopModeEnabled() && source != null && source.getTask() != null) { final Task sourceTask = source.getTask(); outParams.mWindowingMode = sourceTask.getWindowingMode(); appendLog("inherit-from-source=" + outParams.mWindowingMode); @@ -108,23 +105,29 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { return RESULT_SKIP; } - // Update width and height with default desktop mode values - float density = (float) task.getConfiguration().densityDpi / DENSITY_DEFAULT; - final int width = (int) (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f); - final int height = (int) (DESKTOP_MODE_DEFAULT_HEIGHT_DP * density + 0.5f); - outParams.mBounds.right = width; - outParams.mBounds.bottom = height; - - // Center the task in window bounds - Rect windowBounds = task.getWindowConfiguration().getBounds(); - outParams.mBounds.offset(windowBounds.centerX() - outParams.mBounds.centerX(), - windowBounds.centerY() - outParams.mBounds.centerY()); + calculateAndCentreInitialBounds(task, outParams); appendLog("setting desktop mode task bounds to %s", outParams.mBounds); return RESULT_DONE; } + /** + * Calculates the initial height and width of a task in desktop mode and centers it within the + * window bounds. + */ + private void calculateAndCentreInitialBounds(Task task, + LaunchParamsController.LaunchParams outParams) { + // TODO(b/319819547): Account for app constraints so apps do not become letterboxed + final Rect windowBounds = task.getDisplayArea().getBounds(); + final int width = (int) (windowBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int height = (int) (windowBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + outParams.mBounds.right = width; + outParams.mBounds.bottom = height; + outParams.mBounds.offset(windowBounds.centerX() - outParams.mBounds.centerX(), + windowBounds.centerY() - outParams.mBounds.centerY()); + } + private void initLogBuilder(Task task, ActivityRecord activity) { if (DEBUG) { mLogBuilder = new StringBuilder( @@ -140,14 +143,8 @@ public class DesktopModeLaunchParamsModifier implements LaunchParamsModifier { if (DEBUG) Slog.d(TAG, mLogBuilder.toString()); } - /** Whether desktop mode is supported. */ - static boolean isDesktopModeSupported() { - // Check for aconfig flag first - if (ENABLE_DESKTOP_WINDOWING) { - return true; - } - // Fall back to sysprop flag - // TODO(b/304778354): remove sysprop once desktop aconfig flag supports dynamic overriding - return DESKTOP_MODE_PROTO2_SUPPORTED; + /** Whether desktop mode is enabled. */ + static boolean isDesktopModeEnabled() { + return Flags.enableDesktopWindowingMode(); } } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 5cf9acdbc0d6..7f3df958664c 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -47,6 +47,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLO import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; @@ -1533,9 +1534,19 @@ public class DisplayPolicy { // Check the windows that overlap with system bars to determine system bars' appearance. if ((appWindow && attached == null && attrs.isFullscreen()) || attrs.type == TYPE_VOICE_INTERACTION) { - // Record the top-fullscreen-app-window which will be used to determine system UI + + // If this is the exiting starting window, don't let it control the system bars. + // The app window behind it should be the controlling window instead. Reason: when an + // activity starts another activity behind a starting window, the app window of the + // first activity will lose the window focus. And then mTopFullscreenOpaqueWindowState + // will control the system bars. The logic here is to let first app window keep + // controlling system bars until the second app window is ready. + final boolean exitingStartingWindow = + attrs.type == TYPE_APPLICATION_STARTING && win.mAnimatingExit; + + // Record the top-fullscreen-app-window which will be used to determine the system UI // controlling window. - if (mTopFullscreenOpaqueWindowState == null) { + if (mTopFullscreenOpaqueWindowState == null && !exitingStartingWindow) { mTopFullscreenOpaqueWindowState = win; } diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java index b68e67e291e7..34ea4ac35224 100644 --- a/services/core/java/com/android/server/wm/DragDropController.java +++ b/services/core/java/com/android/server/wm/DragDropController.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.view.View.DRAG_FLAG_GLOBAL; import static android.view.View.DRAG_FLAG_GLOBAL_SAME_APPLICATION; +import static android.view.View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG; import static com.android.input.flags.Flags.enablePointerChoreographer; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG; @@ -373,8 +374,11 @@ class DragDropController { boolean notifyUnhandledDrop(DragEvent dropEvent, String reason) { final boolean isLocalDrag = (mDragState.mFlags & (DRAG_FLAG_GLOBAL_SAME_APPLICATION | DRAG_FLAG_GLOBAL)) == 0; + final boolean shouldDelegateUnhandledDrag = + (mDragState.mFlags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) != 0; if (!com.android.window.flags.Flags.delegateUnhandledDrags() || mGlobalDragListener == null + || !shouldDelegateUnhandledDrag || isLocalDrag) { // Skip if the flag is disabled, there is no unhandled-drag listener, or if this is a // purely local drag diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java index 76038b945288..b266caa82056 100644 --- a/services/core/java/com/android/server/wm/DragState.java +++ b/services/core/java/com/android/server/wm/DragState.java @@ -216,8 +216,7 @@ class DragState { mIsClosing = true; // Unregister the input interceptor. if (mInputInterceptor != null) { - if (DEBUG_DRAG) - Slog.d(TAG_WM, "unregistering drag input channel"); + if (DEBUG_DRAG) Slog.d(TAG_WM, "Unregistering drag input channel"); // Input channel should be disposed on the thread where the input is being handled. mDragDropController.sendHandlerMessage( @@ -227,9 +226,7 @@ class DragState { // Send drag end broadcast if drag start has been sent. if (mDragInProgress) { - if (DEBUG_DRAG) { - Slog.d(TAG_WM, "broadcasting DRAG_ENDED"); - } + if (DEBUG_DRAG) Slog.d(TAG_WM, "Broadcasting DRAG_ENDED"); for (WindowState ws : mNotifiedWindows) { float x = 0; float y = 0; @@ -248,6 +245,7 @@ class DragState { x, y, mThumbOffsetX, mThumbOffsetY, null, null, null, dragSurface, null, mDragResult); try { + if (DEBUG_DRAG) Slog.d(TAG_WM, "Sending DRAG_ENDED to " + ws); ws.mClient.dispatchDragEvent(event); } catch (RemoteException e) { Slog.w(TAG_WM, "Unable to drag-end window " + ws); @@ -364,7 +362,7 @@ class DragState { return false; } - if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin); + if (DEBUG_DRAG) Slog.d(TAG_WM, "Sending DROP to " + touchedWin); final IBinder clientToken = touchedWin.mClient.asBinder(); final DragEvent event = createDropEvent(x, y, touchedWin, false /* includePrivateInfo */); @@ -460,7 +458,7 @@ class DragState { */ CompletableFuture<Void> register(Display display) { display.getRealSize(mDisplaySize); - if (DEBUG_DRAG) Slog.d(TAG_WM, "registering drag input channel"); + if (DEBUG_DRAG) Slog.d(TAG_WM, "Registering drag input channel"); if (mInputInterceptor != null) { Slog.e(TAG_WM, "Duplicate register of drag input channel"); return completedFuture(null); @@ -489,7 +487,7 @@ class DragState { mSourceUserId, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE); if (DEBUG_DRAG) { - Slog.d(TAG_WM, "broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")"); + Slog.d(TAG_WM, "Broadcasting DRAG_STARTED at (" + touchX + ", " + touchY + ")"); } final boolean containsAppExtras = containsApplicationExtras(mDataDescription); diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java index 91bb8d007948..97b5925893ae 100644 --- a/services/core/java/com/android/server/wm/LaunchParamsController.java +++ b/services/core/java/com/android/server/wm/LaunchParamsController.java @@ -64,10 +64,7 @@ class LaunchParamsController { void registerDefaultModifiers(ActivityTaskSupervisor supervisor) { // {@link TaskLaunchParamsModifier} handles window layout preferences. registerModifier(new TaskLaunchParamsModifier(supervisor)); - if (DesktopModeLaunchParamsModifier.isDesktopModeSupported()) { - // {@link DesktopModeLaunchParamsModifier} handles default task size changes - registerModifier(new DesktopModeLaunchParamsModifier()); - } + registerModifier(new DesktopModeLaunchParamsModifier()); } /** diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS index e06f2158dc14..79eb0dc620a5 100644 --- a/services/core/java/com/android/server/wm/OWNERS +++ b/services/core/java/com/android/server/wm/OWNERS @@ -24,3 +24,5 @@ per-file Background*Start* = set noparent per-file Background*Start* = file:/BAL_OWNERS per-file Background*Start* = ogunwale@google.com, louischang@google.com +# File related to activity callers +per-file ActivityCallerState.java = file:/core/java/android/app/COMPONENT_CALLER_OWNERS diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index e027eb63f1d5..dd146420c748 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import static android.app.ActivityManager.FLAG_AND_UNLOCKED; import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE; import static android.app.ActivityManager.RECENT_WITH_EXCLUDED; import static android.app.ActivityTaskManager.INVALID_TASK_ID; @@ -69,6 +68,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArraySet; +import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -89,9 +89,9 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; -import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; /** * Class for managing the recent tasks list. The list is ordered by most recent (index 0) to the @@ -167,8 +167,9 @@ class RecentTasks { /** * Mapping of user id -> whether recent tasks have been loaded for that user. + * The AtomicBoolean per user will be locked when reading persisted task from storage. */ - private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray( + private final SparseArray<AtomicBoolean> mUsersWithRecentsLoaded = new SparseArray<>( DEFAULT_INITIAL_CAPACITY); /** @@ -481,29 +482,49 @@ class RecentTasks { /** * Loads the persistent recentTasks for {@code userId} into this list from persistent storage. - * Does nothing if they are already loaded. - * - * @param userId the user Id + * Does nothing if they are already loaded. This may perform IO operation, so the caller should + * not hold a lock. */ - void loadUserRecentsLocked(int userId) { - if (mUsersWithRecentsLoaded.get(userId)) { - // User already loaded, return early - return; + void loadRecentTasksIfNeeded(int userId) { + AtomicBoolean userLoaded; + synchronized (mService.mGlobalLock) { + userLoaded = mUsersWithRecentsLoaded.get(userId); + if (userLoaded == null) { + mUsersWithRecentsLoaded.append(userId, userLoaded = new AtomicBoolean()); + } } + synchronized (userLoaded) { + if (userLoaded.get()) { + // The recent tasks of the user are already loaded. + return; + } + // Read task files from storage. + final SparseBooleanArray persistedTaskIds = + mTaskPersister.readPersistedTaskIdsFromFileForUser(userId); + final TaskPersister.RecentTaskFiles taskFiles = TaskPersister.loadTasksForUser(userId); + synchronized (mService.mGlobalLock) { + restoreRecentTasksLocked(userId, persistedTaskIds, taskFiles); + } + userLoaded.set(true); + } + } - // Load the task ids if not loaded. - loadPersistedTaskIdsForUserLocked(userId); - - // Check if any tasks are added before recents is loaded - final SparseBooleanArray preaddedTasks = new SparseBooleanArray(); - for (final Task task : mTasks) { + /** Restores recent tasks from raw data (the files are already read into memory). */ + private void restoreRecentTasksLocked(int userId, SparseBooleanArray persistedTaskIds, + TaskPersister.RecentTaskFiles taskFiles) { + mTaskPersister.setPersistedTaskIds(userId, persistedTaskIds); + mPersistedTaskIds.put(userId, persistedTaskIds.clone()); + // Check if any tasks are added before recents is loaded. + final IntArray existedTaskIds = new IntArray(); + for (int i = mTasks.size() - 1; i >= 0; i--) { + final Task task = mTasks.get(i); if (task.mUserId == userId && shouldPersistTaskLocked(task)) { - preaddedTasks.put(task.mTaskId, true); + existedTaskIds.add(task.mTaskId); } } - - Slog.i(TAG, "Loading recents for user " + userId + " into memory."); - List<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks); + Slog.i(TAG, "Restoring recents for user " + userId); + final ArrayList<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, taskFiles, + existedTaskIds); // Tasks are ordered from most recent to least recent. Update the last active time to be // in sync with task recency when device reboots, so the most recent task has the @@ -516,37 +537,34 @@ class RecentTasks { mTasks.addAll(tasks); cleanupLocked(userId); - mUsersWithRecentsLoaded.put(userId, true); // If we have tasks added before loading recents, we need to update persistent task IDs. - if (preaddedTasks.size() > 0) { + if (existedTaskIds.size() > 0) { syncPersistentTaskIdsLocked(); } } - private void loadPersistedTaskIdsForUserLocked(int userId) { - // An empty instead of a null set here means that no persistent taskIds were present - // on file when we loaded them. - if (mPersistedTaskIds.get(userId) == null) { - mPersistedTaskIds.put(userId, mTaskPersister.loadPersistedTaskIdsForUser(userId)); - Slog.i(TAG, "Loaded persisted task ids for user " + userId); - } + private boolean isRecentTasksLoaded(int userId) { + final AtomicBoolean userLoaded = mUsersWithRecentsLoaded.get(userId); + return userLoaded != null && userLoaded.get(); } /** * @return whether the {@param taskId} is currently in use for the given user. */ boolean containsTaskId(int taskId, int userId) { - loadPersistedTaskIdsForUserLocked(userId); - return mPersistedTaskIds.get(userId).get(taskId); + final SparseBooleanArray taskIds = mPersistedTaskIds.get(userId); + return taskIds != null && taskIds.get(taskId); } - /** - * @return all the task ids for the user with the given {@param userId}. - */ - SparseBooleanArray getTaskIdsForUser(int userId) { - loadPersistedTaskIdsForUserLocked(userId); - return mPersistedTaskIds.get(userId); + /** Returns all the task ids for the user from {@link #usersWithRecentsLoadedLocked}. */ + SparseBooleanArray getTaskIdsForLoadedUser(int loadedUserId) { + final SparseBooleanArray taskIds = mPersistedTaskIds.get(loadedUserId); + if (taskIds == null) { + Slog.wtf(TAG, "Loaded user without loaded tasks, userId=" + loadedUserId); + return new SparseBooleanArray(); + } + return taskIds; } /** @@ -565,7 +583,7 @@ class RecentTasks { private void syncPersistentTaskIdsLocked() { for (int i = mPersistedTaskIds.size() - 1; i >= 0; i--) { int userId = mPersistedTaskIds.keyAt(i); - if (mUsersWithRecentsLoaded.get(userId)) { + if (isRecentTasksLoaded(userId)) { // Recents are loaded only after task ids are loaded. Therefore, the set of taskids // referenced here should not be null. mPersistedTaskIds.valueAt(i).clear(); @@ -621,7 +639,7 @@ class RecentTasks { int len = 0; for (int i = 0; i < usersWithRecentsLoaded.length; i++) { int userId = mUsersWithRecentsLoaded.keyAt(i); - if (mUsersWithRecentsLoaded.valueAt(i)) { + if (mUsersWithRecentsLoaded.valueAt(i).get()) { usersWithRecentsLoaded[len++] = userId; } } @@ -639,7 +657,7 @@ class RecentTasks { * @param userId the id of the user */ void unloadUserDataFromMemoryLocked(int userId) { - if (mUsersWithRecentsLoaded.get(userId)) { + if (isRecentTasksLoaded(userId)) { Slog.i(TAG, "Unloading recents for user " + userId + " from memory."); mUsersWithRecentsLoaded.delete(userId); removeTasksForUserLocked(userId); @@ -922,11 +940,6 @@ class RecentTasks { return mService.mAmInternal.getCurrentProfileIds(); } - @VisibleForTesting - boolean isUserRunning(int userId, int flags) { - return mService.mAmInternal.isUserRunning(userId, flags); - } - /** * @return the list of recent tasks for presentation. */ @@ -942,13 +955,6 @@ class RecentTasks { private ArrayList<ActivityManager.RecentTaskInfo> getRecentTasksImpl(int maxNum, int flags, boolean getTasksAllowed, int userId, int callingUid) { final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0; - - if (!isUserRunning(userId, FLAG_AND_UNLOCKED)) { - Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents"); - return new ArrayList<>(); - } - loadUserRecentsLocked(userId); - final Set<Integer> includedUsers = getProfileIds(userId); includedUsers.add(Integer.valueOf(userId)); diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index a98b9f7cd1d1..3ef6eeb2ecf3 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -44,7 +44,6 @@ import android.view.SurfaceControl.Transaction; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.protolog.ProtoLogImpl; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.FastPrintWriter; import com.android.server.wm.SurfaceAnimator.AnimationType; @@ -210,7 +209,7 @@ class RemoteAnimationController implements DeathRecipient { Slog.e(TAG, "Failed to start remote animation", e); onAnimationFinished(); } - if (ProtoLogImpl.isEnabled(WM_DEBUG_REMOTE_ANIMATIONS)) { + if (ProtoLog.isEnabled(WM_DEBUG_REMOTE_ANIMATIONS)) { ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation(): Notify animation start:"); writeStartDebugStatement(); } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index b562ccfb3d2b..07a03ebcc9b2 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2158,7 +2158,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> organizedTf.mClearedTaskFragmentForPip = true; } - transitionController.collect(rootTask); + if (isPip2ExperimentEnabled()) { + transitionController.collectExistenceChange(rootTask); + } else { + transitionController.collect(rootTask); + } if (transitionController.isShellTransitionsEnabled()) { // set mode NOW so that when we reparent the activity, it won't be resumed. diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index c3de4d5acc21..d67684c7038e 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -32,7 +32,6 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.protolog.ProtoLogImpl; import com.android.internal.protolog.common.ProtoLog; import java.io.PrintWriter; @@ -193,7 +192,7 @@ public class SurfaceAnimator { return; } mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback); - if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) { + if (ProtoLog.isEnabled(WM_DEBUG_ANIM)) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); mAnimation.dump(pw, ""); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 2bee095e7f46..1353ff09b292 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3750,8 +3750,7 @@ class Task extends TaskFragment { // Boost the adjacent TaskFragment for dimmer if needed. final TaskFragment taskFragment = wc.asTaskFragment(); - if (taskFragment != null && taskFragment.isEmbedded() - && taskFragment.isVisibleRequested()) { + if (taskFragment != null && taskFragment.isEmbedded()) { final TaskFragment adjacentTf = taskFragment.getAdjacentTaskFragment(); if (adjacentTf != null && adjacentTf.shouldBoostDimmer()) { adjacentTf.assignLayer(t, layer++); diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java index 8d054db8994a..24b533a23af6 100644 --- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java @@ -1197,16 +1197,13 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr } } - // TODO(b/204399167): change to push the embedded state to the client side @Override public boolean isActivityEmbedded(IBinder activityToken) { synchronized (mGlobalLock) { final ActivityRecord activity = ActivityRecord.forTokenLocked(activityToken); - if (activity == null) { - return false; - } - final TaskFragment taskFragment = activity.getOrganizedTaskFragment(); - return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride(); + return activity != null + ? activity.isEmbeddedInHostContainer() + : false; } } diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java index 5ec0119725cb..d89dc0b8e81c 100644 --- a/services/core/java/com/android/server/wm/TaskPersister.java +++ b/services/core/java/com/android/server/wm/TaskPersister.java @@ -27,6 +27,7 @@ import android.os.FileUtils; import android.os.SystemClock; import android.util.ArraySet; import android.util.AtomicFile; +import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -43,20 +44,20 @@ import org.xmlpull.v1.XmlPullParser; import java.io.BufferedReader; import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.List; /** * Persister that saves recent tasks into disk. @@ -129,11 +130,9 @@ public class TaskPersister implements PersisterQueue.Listener { ImageWriteQueueItem.class); } + /** Reads task ids from file. This should not be called in lock. */ @NonNull - SparseBooleanArray loadPersistedTaskIdsForUser(int userId) { - if (mTaskIdsInFile.get(userId) != null) { - return mTaskIdsInFile.get(userId).clone(); - } + SparseBooleanArray readPersistedTaskIdsFromFileForUser(int userId) { final SparseBooleanArray persistedTaskIds = new SparseBooleanArray(); synchronized (mIoLock) { BufferedReader reader = null; @@ -154,11 +153,10 @@ public class TaskPersister implements PersisterQueue.Listener { IoUtils.closeQuietly(reader); } } - mTaskIdsInFile.put(userId, persistedTaskIds); - return persistedTaskIds.clone(); + Slog.i(TAG, "Loaded persisted task ids for user " + userId); + return persistedTaskIds; } - @VisibleForTesting void writePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) { if (userId < 0) { @@ -183,6 +181,10 @@ public class TaskPersister implements PersisterQueue.Listener { } } + void setPersistedTaskIds(int userId, @NonNull SparseBooleanArray taskIds) { + mTaskIdsInFile.put(userId, taskIds); + } + void unloadUserDataFromMemory(int userId) { mTaskIdsInFile.delete(userId); } @@ -241,7 +243,7 @@ public class TaskPersister implements PersisterQueue.Listener { return item != null ? item.mImage : null; } - private String fileToString(File file) { + private static String fileToString(File file) { final String newline = System.lineSeparator(); try { BufferedReader reader = new BufferedReader(new FileReader(file)); @@ -272,44 +274,64 @@ public class TaskPersister implements PersisterQueue.Listener { return null; } - List<Task> restoreTasksForUserLocked(final int userId, SparseBooleanArray preaddedTasks) { - final ArrayList<Task> tasks = new ArrayList<Task>(); - ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>(); - - File userTasksDir = getUserTasksDir(userId); - - File[] recentFiles = userTasksDir.listFiles(); + /** Loads task files from disk. This should not be called in lock. */ + static RecentTaskFiles loadTasksForUser(int userId) { + final ArrayList<RecentTaskFile> taskFiles = new ArrayList<>(); + final File userTasksDir = getUserTasksDir(userId); + final File[] recentFiles = userTasksDir.listFiles(); if (recentFiles == null) { - Slog.e(TAG, "restoreTasksForUserLocked: Unable to list files from " + userTasksDir); - return tasks; + Slog.i(TAG, "loadTasksForUser: Unable to list files from " + userTasksDir + + " exists=" + userTasksDir.exists()); + return new RecentTaskFiles(new File[0], taskFiles); } - - for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) { - File taskFile = recentFiles[taskNdx]; - if (DEBUG) { - Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId - + ", taskFile=" + taskFile.getName()); - } - + for (File taskFile : recentFiles) { if (!taskFile.getName().endsWith(TASK_FILENAME_SUFFIX)) { continue; } + final int taskId; try { - final int taskId = Integer.parseInt(taskFile.getName().substring( + taskId = Integer.parseInt(taskFile.getName().substring( 0 /* beginIndex */, taskFile.getName().length() - TASK_FILENAME_SUFFIX.length())); - if (preaddedTasks.get(taskId, false)) { - Slog.w(TAG, "Task #" + taskId + - " has already been created so we don't restore again"); - continue; - } } catch (NumberFormatException e) { Slog.w(TAG, "Unexpected task file name", e); continue; } + try { + taskFiles.add(new RecentTaskFile(taskId, taskFile)); + } catch (IOException e) { + Slog.w(TAG, "Failed to read file: " + fileToString(taskFile), e); + taskFile.delete(); + } + } + return new RecentTaskFiles(recentFiles, taskFiles); + } + + /** Restores tasks from raw bytes (no read storage operation). */ + ArrayList<Task> restoreTasksForUserLocked(int userId, RecentTaskFiles recentTaskFiles, + IntArray existedTaskIds) { + final ArrayList<Task> tasks = new ArrayList<>(); + final ArrayList<RecentTaskFile> taskFiles = recentTaskFiles.mLoadedFiles; + if (taskFiles.isEmpty()) { + return tasks; + } + + final ArraySet<Integer> recoveredTaskIds = new ArraySet<>(); + for (int taskNdx = 0; taskNdx < taskFiles.size(); ++taskNdx) { + final RecentTaskFile recentTask = taskFiles.get(taskNdx); + if (existedTaskIds.contains(recentTask.mTaskId)) { + Slog.w(TAG, "Task #" + recentTask.mTaskId + + " has already been created, so skip restoring"); + continue; + } + final File taskFile = recentTask.mFile; + if (DEBUG) { + Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId + + ", taskFile=" + taskFile.getName()); + } boolean deleteFile = false; - try (InputStream is = new FileInputStream(taskFile)) { + try (InputStream is = recentTask.mXmlContent) { final TypedXmlPullParser in = Xml.resolvePullParser(is); int event; @@ -345,7 +367,7 @@ public class TaskPersister implements PersisterQueue.Listener { } else if (userId != task.mUserId) { // Should not happen. Slog.wtf(TAG, "Task with userId " + task.mUserId + " found in " - + userTasksDir.getAbsolutePath()); + + taskFile.getAbsolutePath()); } else { // Looks fine. mTaskSupervisor.setNextTaskIdForUser(taskId, userId); @@ -377,7 +399,7 @@ public class TaskPersister implements PersisterQueue.Listener { } if (!DEBUG) { - removeObsoleteFiles(recoveredTaskIds, userTasksDir.listFiles()); + removeObsoleteFiles(recoveredTaskIds, recentTaskFiles.mUserTaskFiles); } // Fix up task affiliation from taskIds @@ -456,7 +478,7 @@ public class TaskPersister implements PersisterQueue.Listener { SparseArray<SparseBooleanArray> changedTaskIdsPerUser = new SparseArray<>(); synchronized (mService.mGlobalLock) { for (int userId : mRecentTasks.usersWithRecentsLoadedLocked()) { - SparseBooleanArray taskIdsToSave = mRecentTasks.getTaskIdsForUser(userId); + SparseBooleanArray taskIdsToSave = mRecentTasks.getTaskIdsForLoadedUser(userId); SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId); if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIdsToSave)) { continue; @@ -512,6 +534,30 @@ public class TaskPersister implements PersisterQueue.Listener { return parentDir.isDirectory() || parentDir.mkdir(); } + private static class RecentTaskFile { + final int mTaskId; + final File mFile; + final ByteArrayInputStream mXmlContent; + + RecentTaskFile(int taskId, File file) throws IOException { + mTaskId = taskId; + mFile = file; + mXmlContent = new ByteArrayInputStream(Files.readAllBytes(file.toPath())); + } + } + + static class RecentTaskFiles { + /** All files under the user task directory. */ + final File[] mUserTaskFiles; + /** The successfully loaded files. */ + final ArrayList<RecentTaskFile> mLoadedFiles; + + RecentTaskFiles(File[] userFiles, ArrayList<RecentTaskFile> loadedFiles) { + mUserTaskFiles = userFiles; + mLoadedFiles = loadedFiles; + } + } + private static class TaskWriteQueueItem implements PersisterQueue.WriteQueueItem { private final ActivityTaskManagerService mService; private final Task mTask; diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 001f46d4c36c..594043d380c9 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -58,7 +58,6 @@ import android.window.ScreenCapture; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.protolog.ProtoLogImpl; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.server.wallpaper.WallpaperCropper.WallpaperCropUtils; @@ -336,7 +335,7 @@ class WallpaperController { for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) { final WallpaperWindowToken token = mWallpaperTokens.get(i); token.setVisibility(false); - if (ProtoLogImpl.isEnabled(WM_DEBUG_WALLPAPER) && token.isVisible()) { + if (ProtoLog.isEnabled(WM_DEBUG_WALLPAPER) && token.isVisible()) { ProtoLog.d(WM_DEBUG_WALLPAPER, "Hiding wallpaper %s from %s target=%s prev=%s callers=%s", token, winGoingAway, mWallpaperTarget, mPrevWallpaperTarget, diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 61fde5e31e8f..fd0289edc84b 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -113,7 +113,6 @@ import android.window.WindowContainerToken; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.ColorUtils; -import com.android.internal.protolog.ProtoLogImpl; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.server.wm.SurfaceAnimator.Animatable; @@ -3410,7 +3409,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // ActivityOption#makeCustomAnimation or WindowManager#overridePendingTransition. a.restrictDuration(MAX_APP_TRANSITION_DURATION); } - if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) { + if (ProtoLog.isEnabled(WM_DEBUG_ANIM)) { ProtoLog.i(WM_DEBUG_ANIM, "Loaded animation %s for %s, duration: %d, stack=%s", a, this, ((a != null) ? a.getDuration() : 0), Debug.getCallers(20)); } diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 4698b6b2925c..5df2edc808f6 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -1079,4 +1079,10 @@ public abstract class WindowManagerInternal { * Moves the current focus to the top activity window if the top activity is embedded. */ public abstract boolean moveFocusToTopEmbeddedWindowIfNeeded(); + + /** + * Returns an instance of {@link ScreenCapture.ScreenshotHardwareBuffer} containing the current + * screenshot. + */ + public abstract ScreenCapture.ScreenshotHardwareBuffer takeAssistScreenshot(); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 9b7bc4383e0c..c93cc074aa3d 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -327,8 +327,8 @@ import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IKeyguardLockedStateListener; import com.android.internal.policy.IShortcutService; import com.android.internal.policy.KeyInterceptionInfo; +import com.android.internal.protolog.LegacyProtoLogImpl; import com.android.internal.protolog.ProtoLogGroup; -import com.android.internal.protolog.ProtoLogImpl; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastPrintWriter; @@ -4081,13 +4081,8 @@ public class WindowManagerService extends IWindowManager.Stub } } - /** - * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. - * In portrait mode, it grabs the upper region of the screen based on the vertical dimension - * of the target image. - */ - @Override - public boolean requestAssistScreenshot(final IAssistDataReceiver receiver) { + @Nullable + private ScreenCapture.ScreenshotHardwareBuffer takeAssistScreenshot() { if (!checkCallingPermission(READ_FRAME_BUFFER, "requestAssistScreenshot()")) { throw new SecurityException("Requires READ_FRAME_BUFFER permission"); } @@ -4106,24 +4101,34 @@ public class WindowManagerService extends IWindowManager.Stub } } - final Bitmap bm; + final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer; if (captureArgs != null) { ScreenCapture.SynchronousScreenCaptureListener syncScreenCapture = ScreenCapture.createSyncCaptureListener(); ScreenCapture.captureLayers(captureArgs, syncScreenCapture); - final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer = - syncScreenCapture.getBuffer(); - bm = screenshotBuffer == null ? null : screenshotBuffer.asBitmap(); + screenshotBuffer = syncScreenCapture.getBuffer(); } else { - bm = null; + screenshotBuffer = null; } - if (bm == null) { + if (screenshotBuffer == null) { Slog.w(TAG_WM, "Failed to take screenshot"); } + return screenshotBuffer; + } + + /** + * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. + * In portrait mode, it grabs the upper region of the screen based on the vertical dimension + * of the target image. + */ + @Override + public boolean requestAssistScreenshot(final IAssistDataReceiver receiver) { + final ScreenCapture.ScreenshotHardwareBuffer shb = takeAssistScreenshot(); + final Bitmap bm = shb != null ? shb.asBitmap() : null; FgThread.getHandler().post(() -> { try { receiver.onHandleAssistScreenshot(bm); @@ -6701,7 +6706,11 @@ public class WindowManagerService extends IWindowManager.Stub private void dumpLogStatus(PrintWriter pw) { pw.println("WINDOW MANAGER LOGGING (dumpsys window logging)"); - pw.println(ProtoLogImpl.getSingleInstance().getStatus()); + if (android.tracing.Flags.perfettoProtolog()) { + pw.println("Deprecated legacy command. Use Perfetto commands instead."); + return; + } + ((LegacyProtoLogImpl) ProtoLog.getSingleInstance()).getStatus(); } private void dumpSessionsLocked(PrintWriter pw) { @@ -8684,6 +8693,12 @@ public class WindowManagerService extends IWindowManager.Stub return false; } } + + @Override + public ScreenCapture.ScreenshotHardwareBuffer takeAssistScreenshot() { + // WMS.takeAssistScreenshot takes care of the locking. + return WindowManagerService.this.takeAssistScreenshot(); + } } private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy { diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 8fad9509af44..0b29f9688acd 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -48,7 +48,9 @@ import android.view.IWindowManager; import android.view.ViewDebug; import com.android.internal.os.ByteTransferPipe; -import com.android.internal.protolog.ProtoLogImpl; +import com.android.internal.protolog.LegacyProtoLogImpl; +import com.android.internal.protolog.common.IProtoLog; +import com.android.internal.protolog.common.ProtoLog; import com.android.server.IoThread; import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType; import com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition; @@ -107,11 +109,19 @@ public class WindowManagerShellCommand extends ShellCommand { // trace files can be written. return mInternal.mWindowTracing.onShellCommand(this); case "logging": - int result = ProtoLogImpl.getSingleInstance().onShellCommand(this); - if (result != 0) { - pw.println("Not handled, please use " - + "`adb shell dumpsys activity service SystemUIService WMShell` " - + "if you are looking for ProtoLog in WMShell"); + IProtoLog instance = ProtoLog.getSingleInstance(); + int result = 0; + if (instance instanceof LegacyProtoLogImpl) { + result = ((LegacyProtoLogImpl) instance).onShellCommand(this); + if (result != 0) { + pw.println("Not handled, please use " + + "`adb shell dumpsys activity service SystemUIService " + + "WMShell` if you are looking for ProtoLog in WMShell"); + } + } else { + result = -1; + pw.println("Command not supported. " + + "Only supported when using legacy ProtoLog."); } return result; case "user-rotation": diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 90f5b62b4a08..a7a28c282ff9 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -245,7 +245,6 @@ import android.window.OnBackInvokedCallbackInfo; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.policy.KeyInterceptionInfo; -import com.android.internal.protolog.ProtoLogImpl; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.ToBooleanFunction; @@ -4681,7 +4680,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } void onExitAnimationDone() { - if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) { + if (ProtoLog.isEnabled(WM_DEBUG_ANIM)) { final AnimationAdapter animationAdapter = mSurfaceAnimator.getAnimation(); StringWriter sw = new StringWriter(); if (animationAdapter != null) { diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 6428591d8b8d..7f7c2493cd68 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -60,7 +60,6 @@ import android.view.WindowManager.LayoutParams; import android.view.animation.Animation; import android.view.animation.AnimationUtils; -import com.android.internal.protolog.ProtoLogImpl; import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; @@ -584,7 +583,7 @@ class WindowStateAnimator { mWin.mAttrs, attr, TRANSIT_OLD_NONE); } } - if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) { + if (ProtoLog.isEnabled(WM_DEBUG_ANIM)) { ProtoLog.v(WM_DEBUG_ANIM, "applyAnimation: win=%s" + " anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s", this, anim, attr, a, transit, mAttrType, isEntrance, Debug.getCallers(20)); diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java index 416d0427a0d6..424d50434010 100644 --- a/services/core/java/com/android/server/wm/WindowTracing.java +++ b/services/core/java/com/android/server/wm/WindowTracing.java @@ -35,7 +35,9 @@ import android.util.Log; import android.util.proto.ProtoOutputStream; import android.view.Choreographer; -import com.android.internal.protolog.ProtoLogImpl; +import com.android.internal.protolog.LegacyProtoLogImpl; +import com.android.internal.protolog.common.IProtoLog; +import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.TraceBuffer; import java.io.File; @@ -77,6 +79,8 @@ class WindowTracing { private volatile boolean mEnabledLockFree; private boolean mScheduled; + private final IProtoLog mProtoLog; + static WindowTracing createDefaultAndStartLooper(WindowManagerService service, Choreographer choreographer) { File file = new File(TRACE_FILENAME); @@ -96,6 +100,7 @@ class WindowTracing { mTraceFile = file; mBuffer = new TraceBuffer(bufferCapacity); setLogLevel(WindowTraceLogLevel.TRIM, null /* pw */); + mProtoLog = ProtoLog.getSingleInstance(); } void startTrace(@Nullable PrintWriter pw) { @@ -104,7 +109,6 @@ class WindowTracing { return; } synchronized (mEnabledLock) { - ProtoLogImpl.getSingleInstance().startProtoLog(pw); logAndPrintln(pw, "Start tracing to " + mTraceFile + "."); mBuffer.resetBuffer(); mEnabled = mEnabledLockFree = true; @@ -132,7 +136,6 @@ class WindowTracing { writeTraceToFileLocked(); logAndPrintln(pw, "Trace written to " + mTraceFile + "."); } - ProtoLogImpl.getSingleInstance().stopProtoLog(pw, true); } /** @@ -152,11 +155,15 @@ class WindowTracing { logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush."); writeTraceToFileLocked(); logAndPrintln(pw, "Trace written to " + mTraceFile + "."); - ProtoLogImpl.getSingleInstance().stopProtoLog(pw, true); + if (!android.tracing.Flags.perfettoProtolog()) { + ((LegacyProtoLogImpl) mProtoLog).stopProtoLog(pw, true); + } logAndPrintln(pw, "Start tracing to " + mTraceFile + "."); mBuffer.resetBuffer(); mEnabled = mEnabledLockFree = true; - ProtoLogImpl.getSingleInstance().startProtoLog(pw); + if (!android.tracing.Flags.perfettoProtolog()) { + ((LegacyProtoLogImpl) mProtoLog).startProtoLog(pw); + } } } diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp index f5e6c45c75b8..f47a59d6cec9 100644 --- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp +++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp @@ -370,6 +370,7 @@ static jboolean vibratorGetInfo(JNIEnv* env, jclass /* clazz */, jlong ptr, return JNI_FALSE; } vibrator::Info info = wrapper->getVibratorInfo(); + info.logFailures(); if (info.capabilities.isOk()) { env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setCapabilities, @@ -443,7 +444,7 @@ static jboolean vibratorGetInfo(JNIEnv* env, jclass /* clazz */, jlong ptr, env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setFrequencyProfile, frequencyProfile); - return info.isFailedLogged("vibratorGetInfo") ? JNI_FALSE : JNI_TRUE; + return info.shouldRetry() ? JNI_FALSE : JNI_TRUE; } static const JNINativeMethod method_table[] = { diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java index 9d45cfb2fb7e..027337f04b6e 100644 --- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java +++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java @@ -18,7 +18,6 @@ package com.android.server.credentials; import static android.credentials.selection.Constants.EXTRA_FINAL_RESPONSE_RECEIVER; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; @@ -161,26 +160,6 @@ public class CredentialManagerUi { */ public PendingIntent createPendingIntent( RequestInfo requestInfo, ArrayList<ProviderData> providerDataList) { - return createPendingIntent(requestInfo, providerDataList, /*forAutofill=*/ false); - } - - /** - * Creates a {@link PendingIntent} to be used to invoke the credential manager selector UI, - * by the calling app process. This intent is invoked from the Autofill flow, when the user - * requests to bring up the 'All Options' page of the credential bottom-sheet. When the user - * clicks on the pinned entry, the intent will bring up the 'All Options' page of the - * bottom-sheet. The provider data list is processed by the credential autofill service for - * each autofill id and passed in as an auth extra. - * - * @param requestInfo the information about the request - */ - public PendingIntent createPendingIntentForAutofill(RequestInfo requestInfo) { - return createPendingIntent(requestInfo, /*providerDataList=*/ null, /*forAutofill=*/ true); - } - - private PendingIntent createPendingIntent( - RequestInfo requestInfo, @Nullable ArrayList<ProviderData> providerDataList, - boolean forAutofill) { List<CredentialProviderInfo> allProviders = CredentialProviderInfoFactory.getCredentialProviderServices( mContext, @@ -196,15 +175,9 @@ public class CredentialManagerUi { disabledProvider.getComponentName().flattenToString())).toList(); Intent intent; - if (forAutofill) { - intent = IntentFactory.createCredentialSelectorIntentForAutofill( - mContext, requestInfo, new ArrayList<>(disabledProviderDataList), - mResultReceiver); - } else { - intent = IntentFactory.createCredentialSelectorIntent( - mContext, requestInfo, providerDataList, - new ArrayList<>(disabledProviderDataList), mResultReceiver); - } + intent = IntentFactory.createCredentialSelectorIntent( + mContext, requestInfo, providerDataList, + new ArrayList<>(disabledProviderDataList), mResultReceiver); intent.setAction(UUID.randomUUID().toString()); //TODO: Create unique pending intent using request code and cancel any pre-existing pending // intents @@ -213,4 +186,21 @@ public class CredentialManagerUi { PendingIntent.FLAG_MUTABLE, /*options=*/null, UserHandle.of(mUserId)); } + + /** + * Creates an {@link Intent} to be used to invoke the credential manager selector UI, + * by the calling app process. This intent is invoked from the Autofill flow, when the user + * requests to bring up the 'All Options' page of the credential bottom-sheet. When the user + * clicks on the pinned entry, the intent will bring up the 'All Options' page of the + * bottom-sheet. The provider data list is processed by the credential autofill service for + * each autofill id and passed in as extras in the pending intent set as authentication + * of the pinned entry. + * + * @param requestInfo the information about the request + */ + public Intent createIntentForAutofill(RequestInfo requestInfo) { + return IntentFactory.createCredentialSelectorIntentForAutofill( + mContext, requestInfo, new ArrayList<>(), + mResultReceiver); + } } diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java index 723c52f37574..3cb98eb4cd7a 100644 --- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java +++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java @@ -20,6 +20,7 @@ import android.Manifest; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.credentials.Constants; import android.credentials.CredentialProviderInfo; import android.credentials.GetCandidateCredentialsException; @@ -114,8 +115,7 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ return; } - cancelExistingPendingIntent(); - mPendingIntent = mCredentialManagerUi.createPendingIntentForAutofill( + Intent intent = mCredentialManagerUi.createIntentForAutofill( RequestInfo.newGetRequestInfo( mRequestId, mClientRequest, mClientAppInfo.getPackageName(), PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(), @@ -129,7 +129,7 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ try { invokeClientCallbackSuccess(new GetCandidateCredentialsResponse( - candidateProviderDataList, mPendingIntent)); + candidateProviderDataList, intent)); } catch (RemoteException e) { Slog.e(TAG, "Issue while responding to client with error : " + e); } @@ -150,7 +150,8 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ @Override public void onFinalErrorReceived(ComponentName componentName, String errorType, String message) { - respondToClientWithErrorAndFinish(errorType, message); + Slog.d(TAG, "onFinalErrorReceived"); + respondToFinalReceiverWithFailureAndFinish(this.mFinalResponseReceiver, errorType, message); } @Override @@ -163,6 +164,13 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ message = "The UI was interrupted - please try again."; } mRequestSessionMetric.collectFrameworkException(exception); + respondToFinalReceiverWithFailureAndFinish(finalResponseReceiver, exception, message); + } + + private void respondToFinalReceiverWithFailureAndFinish( + ResultReceiver finalResponseReceiver, + String exception, String message + ) { if (finalResponseReceiver != null) { Bundle resultData = new Bundle(); resultData.putStringArray( @@ -170,16 +178,16 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ new String[] {exception, message}); finalResponseReceiver.send(Constants.FAILURE_CREDMAN_SELECTOR, resultData); } else { - respondToClientWithErrorAndFinish(exception, message); + Slog.w(TAG, "onUiCancellation called but finalResponseReceiver not found"); } + finishSession(/*propagateCancellation=*/false); } @Override public void onUiSelectorInvocationFailure() { String exception = GetCandidateCredentialsException.TYPE_NO_CREDENTIAL; mRequestSessionMetric.collectFrameworkException(exception); - respondToClientWithErrorAndFinish(exception, - "No credentials available."); + // TODO(): Propagate through final receiver } @Override diff --git a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java index 21ac9e44de65..bc8c2b07f427 100644 --- a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java +++ b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java @@ -82,7 +82,7 @@ public class PendingIntentResultHandler { if (resultData == null) { return null; } - return resultData.getParcelableExtra( + return resultData.getSerializableExtra( CredentialProviderService.EXTRA_CREATE_CREDENTIAL_EXCEPTION, CreateCredentialException.class); } @@ -94,7 +94,7 @@ public class PendingIntentResultHandler { if (resultData == null) { return null; } - return resultData.getParcelableExtra( + return resultData.getSerializableExtra( CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION, GetCredentialException.class); } diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java index fa63bc899cb5..cad9a09247e6 100644 --- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java +++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java @@ -93,7 +93,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential android.credentials.GetCredentialRequest filteredRequest = filterOptions(providerInfo.getCapabilities(), getRequestSession.mClientRequest, - providerInfo); + providerInfo, getRequestSession.mHybridService); if (filteredRequest != null) { Map<String, CredentialOption> beginGetOptionToCredentialOptionMap = new HashMap<>(); @@ -129,7 +129,7 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential android.credentials.GetCredentialRequest filteredRequest = filterOptions(providerInfo.getCapabilities(), getRequestSession.mClientRequest, - providerInfo); + providerInfo, getRequestSession.mHybridService); if (filteredRequest != null) { Map<String, CredentialOption> beginGetOptionToCredentialOptionMap = new HashMap<>(); @@ -179,9 +179,19 @@ public final class ProviderGetSession extends ProviderSession<BeginGetCredential private static android.credentials.GetCredentialRequest filterOptions( List<String> providerCapabilities, android.credentials.GetCredentialRequest clientRequest, - CredentialProviderInfo info - ) { + CredentialProviderInfo info, + String hybridService) { Slog.i(TAG, "Filtering request options for: " + info.getComponentName()); + if (android.credentials.flags.Flags.hybridFilterFixEnabled()) { + ComponentName hybridComponentName = ComponentName.unflattenFromString(hybridService); + if (hybridComponentName != null && hybridComponentName + .equals(info.getComponentName())) { + Slog.i(TAG, "Skipping filtering of options for hybrid service"); + return clientRequest; + } + Slog.w(TAG, "Could not parse hybrid service while filtering options"); + } + List<CredentialOption> filteredOptions = new ArrayList<>(); for (CredentialOption option : clientRequest.getCredentialOptions()) { if (providerCapabilities.contains(option.getType()) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java index df7f3084aeb3..1000bfa5f6c9 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java @@ -53,7 +53,17 @@ class EnterpriseSpecificIdCalculator { TelephonyManager telephonyService = context.getSystemService(TelephonyManager.class); Preconditions.checkState(telephonyService != null, "Unable to access telephony service"); mImei = telephonyService.getImei(0); - mMeid = telephonyService.getMeid(0); + String meid; + try { + meid = telephonyService.getMeid(0); + } catch (UnsupportedOperationException doesNotSupportCdma) { + // Instead of catching the exception, we could check for FEATURE_TELEPHONY_CDMA. + // However that runs the risk of changing a device's existing ESID if on these devices + // telephonyService.getMeid() actually returns non-null even when the device does not + // declare FEATURE_TELEPHONY_CDMA. + meid = null; + } + mMeid = meid; mSerialNumber = Build.getSerial(); WifiManager wifiManager = context.getSystemService(WifiManager.class); Preconditions.checkState(wifiManager != null, "Unable to access WiFi service"); diff --git a/services/fakes/Android.bp b/services/fakes/Android.bp new file mode 100644 index 000000000000..148054b31e89 --- /dev/null +++ b/services/fakes/Android.bp @@ -0,0 +1,20 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +// NOTE: These "fake" services are intended for use under the Ravenwood +// deviceless test environment, and should *not* be included in the build +// artifacts for physical devices, as they already supply "real" services +filegroup { + name: "services.fakes-sources", + srcs: [ + "java/**/*.java", + ], + path: "java", + visibility: ["//frameworks/base"], +} diff --git a/services/fakes/java/com/android/server/FakeClipboardService.java b/services/fakes/java/com/android/server/FakeClipboardService.java new file mode 100644 index 000000000000..01016219e73d --- /dev/null +++ b/services/fakes/java/com/android/server/FakeClipboardService.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.content.ClipData; +import android.content.ClipDescription; +import android.content.Context; +import android.content.IClipboard; +import android.content.IOnPrimaryClipChangedListener; +import android.os.PermissionEnforcer; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.os.UserHandle; + +import com.android.internal.util.Preconditions; + +/** + * Fake implementation of {@code ClipboardManager} since the real implementation is tightly + * coupled with many other internal services. + */ +public class FakeClipboardService extends IClipboard.Stub { + private final RemoteCallbackList<IOnPrimaryClipChangedListener> mListeners = + new RemoteCallbackList<>(); + + private ClipData mPrimaryClip; + private String mPrimaryClipSource; + + public FakeClipboardService(Context context) { + super(PermissionEnforcer.fromContext(context)); + } + + public static class Lifecycle extends SystemService { + private FakeClipboardService mService; + + public Lifecycle(Context context) { + super(context); + } + + @Override + public void onStart() { + mService = new FakeClipboardService(getContext()); + publishBinderService(Context.CLIPBOARD_SERVICE, mService); + } + } + + private static void checkArguments(int userId, int deviceId) { + Preconditions.checkArgument(userId == UserHandle.USER_SYSTEM, + "Fake only supports USER_SYSTEM user"); + Preconditions.checkArgument(deviceId == Context.DEVICE_ID_DEFAULT, + "Fake only supports DEVICE_ID_DEFAULT device"); + } + + private void dispatchPrimaryClipChanged() { + mListeners.broadcast((listener) -> { + try { + listener.dispatchPrimaryClipChanged(); + } catch (RemoteException ignored) { + } + }); + } + + @Override + public void setPrimaryClip(ClipData clip, String callingPackage, String attributionTag, + int userId, int deviceId) { + checkArguments(userId, deviceId); + mPrimaryClip = clip; + mPrimaryClipSource = callingPackage; + dispatchPrimaryClipChanged(); + } + + @Override + @android.annotation.EnforcePermission(android.Manifest.permission.SET_CLIP_SOURCE) + public void setPrimaryClipAsPackage(ClipData clip, String callingPackage, String attributionTag, + int userId, int deviceId, String sourcePackage) { + setPrimaryClipAsPackage_enforcePermission(); + checkArguments(userId, deviceId); + mPrimaryClip = clip; + mPrimaryClipSource = sourcePackage; + dispatchPrimaryClipChanged(); + } + + @Override + public void clearPrimaryClip(String callingPackage, String attributionTag, int userId, + int deviceId) { + checkArguments(userId, deviceId); + mPrimaryClip = null; + mPrimaryClipSource = null; + dispatchPrimaryClipChanged(); + } + + @Override + public ClipData getPrimaryClip(String pkg, String attributionTag, int userId, int deviceId) { + checkArguments(userId, deviceId); + return mPrimaryClip; + } + + @Override + public ClipDescription getPrimaryClipDescription(String callingPackage, String attributionTag, + int userId, int deviceId) { + checkArguments(userId, deviceId); + return (mPrimaryClip != null) ? mPrimaryClip.getDescription() : null; + } + + @Override + public boolean hasPrimaryClip(String callingPackage, String attributionTag, int userId, + int deviceId) { + checkArguments(userId, deviceId); + return mPrimaryClip != null; + } + + @Override + public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener, + String callingPackage, String attributionTag, int userId, int deviceId) { + checkArguments(userId, deviceId); + mListeners.register(listener); + } + + @Override + public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener, + String callingPackage, String attributionTag, int userId, int deviceId) { + checkArguments(userId, deviceId); + mListeners.unregister(listener); + } + + @Override + public boolean hasClipboardText(String callingPackage, String attributionTag, int userId, + int deviceId) { + checkArguments(userId, deviceId); + return (mPrimaryClip != null) && (mPrimaryClip.getItemCount() > 0) + && (mPrimaryClip.getItemAt(0).getText() != null); + } + + @Override + @android.annotation.EnforcePermission(android.Manifest.permission.SET_CLIP_SOURCE) + public String getPrimaryClipSource(String callingPackage, String attributionTag, int userId, + int deviceId) { + getPrimaryClipSource_enforcePermission(); + checkArguments(userId, deviceId); + return mPrimaryClipSource; + } + + @Override + public boolean areClipboardAccessNotificationsEnabledForUser(int userId) { + throw new UnsupportedOperationException(); + } + + @Override + public void setClipboardAccessNotificationsEnabledForUser(boolean enable, int userId) { + throw new UnsupportedOperationException(); + } +} diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/Android.bp b/services/tests/PackageManagerServiceTests/preverifieddomains/Android.bp new file mode 100644 index 000000000000..39ef50112cba --- /dev/null +++ b/services/tests/PackageManagerServiceTests/preverifieddomains/Android.bp @@ -0,0 +1,38 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package { + default_team: "trendy_team_framework_android_packages", + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test { + name: "PreVerifiedDomainsTests", + srcs: [ + "src/**/*.kt", + ], + static_libs: [ + "compatibility-device-util-axt", + "androidx.test.runner", + "truth", + ], + platform_apis: true, + certificate: "platform", + test_suites: ["device-tests"], +} diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidManifest.xml new file mode 100644 index 000000000000..ad731fc1a61c --- /dev/null +++ b/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidManifest.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.android.server.pm.test.preverifieddomains"> + + <application android:label="PreVerified Domains Tests"> + <activity + android:name="com.android.server.pm.test.preverifieddomains.FakeInstantAppInstallerActivity" + android:enabled="true" + android:exported="true"> + <intent-filter> + <action android:name="android.intent.action.INSTALL_INSTANT_APP_PACKAGE_TEST" /> + <category android:name="android.intent.category.DEFAULT"/> + <data android:scheme="file"/> + <data android:mimeType="application/vnd.android.package-archive"/> + </intent-filter> + </activity> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:targetPackage="com.android.server.pm.test.preverifieddomains" + android:label="Package Manager Service Tests for pre-verified domains"> + </instrumentation> + +</manifest> + diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidTest.xml b/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidTest.xml new file mode 100644 index 000000000000..45e193b03e36 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidTest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<configuration description="Runs Package Manager Service Pre-Verified Domains Tests."> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="PreVerifiedDomainsTests.apk" /> + </target_preparer> + + <option name="test-tag" value="PreVerifiedDomainsTests" /> + <test class="com.android.tradefed.testtype.AndroidJUnitTest"> + <option name="package" value="com.android.server.pm.test.preverifieddomains" /> + <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> + <option name="hidden-api-checks" value="false" /> + </test> +</configuration> diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/FakeInstantAppInstallerActivity.kt b/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/FakeInstantAppInstallerActivity.kt new file mode 100644 index 000000000000..d330490516f4 --- /dev/null +++ b/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/FakeInstantAppInstallerActivity.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.pm.test.preverifieddomains + +import android.app.Activity + +class FakeInstantAppInstallerActivity : Activity() diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/PreVerifiedDomainsTests.kt b/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/PreVerifiedDomainsTests.kt new file mode 100644 index 000000000000..70432168ca5c --- /dev/null +++ b/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/PreVerifiedDomainsTests.kt @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.pm.test.preverifieddomains + +import android.app.UiAutomation +import android.content.ComponentName +import android.content.Context +import android.content.pm.Flags +import android.content.pm.PackageInstaller +import android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL +import android.content.pm.PackageManager +import android.os.Build +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.CheckFlagsRule +import android.platform.test.flag.junit.DeviceFlagsValueProvider +import android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import com.android.compatibility.common.util.DeviceConfigStateManager +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.AfterClass +import org.junit.Assert.assertThrows +import org.junit.Assume.assumeTrue +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Rule +import org.junit.Test +import org.junit.function.ThrowingRunnable +import org.junit.runner.RunWith + +/** + * Pre-verified domains API tests. These tests require the device's default instant app + * installer to be disabled temporarily and is only able to run on ENG builds. + */ +@RunWith(AndroidJUnit4::class) +class PreVerifiedDomainsTests { + companion object { + private const val PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT = + "pre_verified_domains_count_limit" + private const val PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT = + "pre_verified_domain_length_limit" + private const val TEMP_COUNT_LIMIT = 10 + private const val TEMP_LENGTH_LIMIT = 15 + private val testDomains = setOf("com.foo", "com.bar") + + private val uiAutomation: UiAutomation = + InstrumentationRegistry.getInstrumentation().getUiAutomation() + private lateinit var packageManager: PackageManager + private var defaultInstantAppInstaller: ComponentName? = null + private lateinit var fakeInstantAppInstaller: ComponentName + + @JvmStatic + @BeforeClass + fun setupBeforeClass() { + val context = InstrumentationRegistry.getInstrumentation().getContext() + packageManager = context.packageManager + defaultInstantAppInstaller = packageManager.getInstantAppInstallerComponent() + fakeInstantAppInstaller = ComponentName( + context.packageName, + context.packageName + ".FakeInstantAppInstallerActivity") + // By disabling the original instant app installer, this test app becomes the instant + // app installer + uiAutomation.adoptShellPermissionIdentity() + try { + // Enable the fake instant app installer before disabling the default one + packageManager.setComponentEnabledSetting( + fakeInstantAppInstaller, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP + ) + if (defaultInstantAppInstaller != null) { + packageManager.setComponentEnabledSetting( + defaultInstantAppInstaller!!, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + 0 + ) + } + } finally { + uiAutomation.dropShellPermissionIdentity() + } + assertThat(fakeInstantAppInstaller).isEqualTo( + packageManager.getInstantAppInstallerComponent()) + } + + @JvmStatic + @AfterClass + fun restoreInstantAppInstaller() { + uiAutomation.adoptShellPermissionIdentity() + try { + // Enable the original instant app installer before disabling the temporary one, so + // there won't be a time when the device doesn't have a valid instant app installer + if (defaultInstantAppInstaller != null) { + packageManager.setComponentEnabledSetting( + defaultInstantAppInstaller!!, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + 0 + ) + } + // Be careful not to let this test process killed, or the test will be considered + // as failed + packageManager.setComponentEnabledSetting( + fakeInstantAppInstaller, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP + ) + } finally { + uiAutomation.dropShellPermissionIdentity() + } + } + } + + private lateinit var packageInstaller: PackageInstaller + private lateinit var context: Context + private lateinit var packageManager: PackageManager + private var mDefaultCountLimit: String? = null + private var mDefaultLengthLimit: String? = null + + @JvmField + @Rule + val mCheckFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + + @Before + fun setUp() { + context = InstrumentationRegistry.getInstrumentation().getContext() + packageManager = context.packageManager + packageInstaller = packageManager.packageInstaller + mDefaultCountLimit = getLimitFromDeviceConfig(PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT) + mDefaultLengthLimit = getLimitFromDeviceConfig(PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT) + } + + @After + fun cleanUp() { + setLimitInDeviceConfig(PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT, mDefaultCountLimit) + setLimitInDeviceConfig(PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT, mDefaultLengthLimit) + } + + @RequiresFlagsEnabled(Flags.FLAG_SET_PRE_VERIFIED_DOMAINS) + @Test + fun testSetPreVerifiedDomainsExceedsCountLimit() { + // Temporarily change the count limit to a much smaller number so the test can exceed it + setLimitInDeviceConfig( + PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT, + TEMP_COUNT_LIMIT.toString() + ) + val domains = mutableSetOf<String>() + for (i in 0 until(TEMP_COUNT_LIMIT + 1)) { + domains.add("domain$i") + } + + uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.ACCESS_INSTANT_APPS) + try { + assertThrows( + IllegalArgumentException::class.java, + ThrowingRunnable { + createSessionWithPreVerifiedDomains(domains) + } + ) + } finally { + uiAutomation.dropShellPermissionIdentity() + } + } + + @RequiresFlagsEnabled(Flags.FLAG_SET_PRE_VERIFIED_DOMAINS) + @Test + fun testSetPreVerifiedDomainsExceedsLengthLimit() { + // Temporarily change the count limit to a much smaller number so the test can exceed it + setLimitInDeviceConfig( + PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT, + TEMP_LENGTH_LIMIT.toString() + ) + val invalidDomain = "a".repeat(TEMP_LENGTH_LIMIT + 1) + + uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.ACCESS_INSTANT_APPS) + try { + assertThrows( + "Pre-verified domain: [" + + invalidDomain + " ] exceeds maximum length allowed: " + + TEMP_LENGTH_LIMIT, + IllegalArgumentException::class.java, + ThrowingRunnable { + createSessionWithPreVerifiedDomains(setOf(invalidDomain)) + } + ) + } finally { + uiAutomation.dropShellPermissionIdentity() + } + } + + @RequiresFlagsEnabled(Flags.FLAG_SET_PRE_VERIFIED_DOMAINS) + @Test + fun testSetAndGetPreVerifiedDomains() { + // Fake instant app installers can only work on ENG builds + assumeTrue("eng" == Build.TYPE) + var session: PackageInstaller.Session? = null + uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.ACCESS_INSTANT_APPS) + try { + val sessionId = createSessionWithPreVerifiedDomains(testDomains) + session = packageInstaller.openSession(sessionId) + assertThat(session.getPreVerifiedDomains()).isEqualTo(testDomains) + } finally { + uiAutomation.dropShellPermissionIdentity() + session?.abandon() + } + } + + private fun createSessionWithPreVerifiedDomains(domains: Set<String>): Int { + val sessionParam = PackageInstaller.SessionParams(MODE_FULL_INSTALL) + val sessionId = packageInstaller.createSession(sessionParam) + val session = packageInstaller.openSession(sessionId) + try { + session.setPreVerifiedDomains(domains) + } catch (e: Exception) { + session.abandon() + throw e + } + return sessionId + } + + private fun getLimitFromDeviceConfig(propertyName: String): String? { + val stateManager = DeviceConfigStateManager( + context, + NAMESPACE_PACKAGE_MANAGER_SERVICE, + propertyName + ) + return stateManager.get() + } + + private fun setLimitInDeviceConfig(propertyName: String, value: String?) { + val stateManager = DeviceConfigStateManager( + context, + NAMESPACE_PACKAGE_MANAGER_SERVICE, + propertyName + ) + val currentValue = stateManager.get() + if (currentValue != value) { + // Only change the value if the current value is different + stateManager.set(value) + } + } +} diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt index d4b57f191ecd..96e9ca0c19b5 100644 --- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt +++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt @@ -275,6 +275,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag AndroidPackage::isUpdatableSystem, AndroidPackage::getEmergencyInstaller, AndroidPackage::isAllowCrossUidActivitySwitchFromBelow, + PackageImpl::isAppMetadataFileInApk, ) override fun extraParams() = listOf( diff --git a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java index 418b78cd696b..9c9aeeaadb71 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java @@ -16,6 +16,7 @@ package com.android.server.display; +import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED; import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED; import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT; import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE; @@ -1016,4 +1017,34 @@ public class AutomaticBrightnessControllerTest { listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500)); assertEquals(500, mController.getAmbientLux(), EPSILON); } + + @Test + public void testBrightnessBasedOnLastObservedLux() throws Exception { + ArgumentCaptor<SensorEventListener> listenerCaptor = + ArgumentCaptor.forClass(SensorEventListener.class); + verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), + eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class)); + SensorEventListener listener = listenerCaptor.getValue(); + + // Set up system to return 0.3f as a brightness value + float lux = 100.0f; + // Brightness as float (from 0.0f to 1.0f) + float normalizedBrightness = 0.3f; + when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)).thenReturn(lux); + when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)).thenReturn(lux); + when(mBrightnessMappingStrategy.getBrightness(eq(lux), eq(null), anyInt())) + .thenReturn(normalizedBrightness); + when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT); + when(mBrightnessThrottler.isThrottled()).thenReturn(true); + + // Send a new sensor value, disable the sensor and verify + listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux)); + mController.configure(AUTO_BRIGHTNESS_DISABLED, /* configuration= */ null, + /* brightness= */ 0, /* userChangedBrightness= */ false, /* adjustment= */ 0, + /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT, + /* shouldResetShortTermModel= */ true); + assertEquals(normalizedBrightness, + mController.getAutomaticScreenBrightnessBasedOnLastObservedLux( + /* brightnessEvent= */ null), EPSILON); + } } diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java index 807774f90655..acddc9d22953 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -1665,6 +1665,35 @@ public final class DisplayPowerControllerTest { /* luxTimestamps= */ any()); } + @Test + public void testInitialDozeBrightness() { + when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(true); + when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true); + mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SCREEN_BRIGHTNESS_MODE, + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); + mContext.getOrCreateTestableResources().addOverride( + com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false); + float brightness = 0.277f; + when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); + when(mHolder.automaticBrightnessController + .getAutomaticScreenBrightnessBasedOnLastObservedLux(any(BrightnessEvent.class))) + .thenReturn(brightness); + when(mHolder.hbmController.getCurrentBrightnessMax()) + .thenReturn(PowerManager.BRIGHTNESS_MAX); + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_DOZE; + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.animator).animateTo(eq(brightness), + /* linearSecondTarget= */ anyFloat(), /* rate= */ anyFloat(), + /* ignoreAnimationLimits= */ anyBoolean()); + } + /** * Creates a mock and registers it to {@link LocalServices}. */ diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java index c0c63c69add8..060f99b4317a 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java @@ -16,9 +16,12 @@ package com.android.server.display.brightness; +import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE; + import static org.junit.Assert.assertEquals; import android.hardware.display.BrightnessInfo; +import android.view.Display; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -39,6 +42,7 @@ public final class BrightnessEventTest { mBrightnessEvent.setReason( getReason(BrightnessReason.REASON_DOZE, BrightnessReason.MODIFIER_LOW_POWER)); mBrightnessEvent.setPhysicalDisplayId("test"); + mBrightnessEvent.setDisplayState(Display.STATE_ON); mBrightnessEvent.setLux(100.0f); mBrightnessEvent.setPreThresholdLux(150.0f); mBrightnessEvent.setTime(System.currentTimeMillis()); @@ -55,6 +59,7 @@ public final class BrightnessEventTest { mBrightnessEvent.setAdjustmentFlags(0); mBrightnessEvent.setAutomaticBrightnessEnabled(true); mBrightnessEvent.setDisplayBrightnessStrategyName(DISPLAY_BRIGHTNESS_STRATEGY_NAME); + mBrightnessEvent.setAutoBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE); } @Test @@ -69,20 +74,20 @@ public final class BrightnessEventTest { public void testToStringWorksAsExpected() { String actualString = mBrightnessEvent.toString(false); String expectedString = - "BrightnessEvent: disp=1, physDisp=test, brt=0.6, initBrt=25.0, rcmdBrt=0.6," - + " preBrt=NaN, lux=100.0, preLux=150.0, hbmMax=0.62, hbmMode=off, rbcStrength=-1," - + " thrmMax=0.65, powerFactor=0.2, wasShortTermModelActive=true, flags=," - + " reason=doze [ low_pwr ], autoBrightness=true, strategy=" - + DISPLAY_BRIGHTNESS_STRATEGY_NAME; + "BrightnessEvent: disp=1, physDisp=test, displayState=ON, brt=0.6, initBrt=25.0," + + " rcmdBrt=0.6, preBrt=NaN, lux=100.0, preLux=150.0, hbmMax=0.62, hbmMode=off," + + " rbcStrength=-1, thrmMax=0.65, powerFactor=0.2, wasShortTermModelActive=true," + + " flags=, reason=doze [ low_pwr ], autoBrightness=true, strategy=" + + DISPLAY_BRIGHTNESS_STRATEGY_NAME + ", autoBrightnessMode=idle"; assertEquals(expectedString, actualString); } @Test public void testFlagsToString() { mBrightnessEvent.reset(); - mBrightnessEvent.setFlags(mBrightnessEvent.getFlags() | BrightnessEvent.FLAG_IDLE_CURVE); + mBrightnessEvent.setFlags(mBrightnessEvent.getFlags() | BrightnessEvent.FLAG_RBC); String actualString = mBrightnessEvent.flagsToString(); - String expectedString = "idle_curve "; + String expectedString = "rbc "; assertEquals(expectedString, actualString); } @@ -90,10 +95,10 @@ public final class BrightnessEventTest { public void testFlagsToString_multipleFlags() { mBrightnessEvent.reset(); mBrightnessEvent.setFlags(mBrightnessEvent.getFlags() - | BrightnessEvent.FLAG_IDLE_CURVE + | BrightnessEvent.FLAG_RBC | BrightnessEvent.FLAG_LOW_POWER_MODE); String actualString = mBrightnessEvent.flagsToString(); - String expectedString = "idle_curve low_power_mode "; + String expectedString = "rbc low_power_mode "; assertEquals(expectedString, actualString); } diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java index 5408e1143330..886780655de2 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java @@ -359,11 +359,17 @@ public class AutomaticBrightnessStrategyTest { AutomaticBrightnessController.class); when(automaticBrightnessController.getAutomaticScreenBrightness(any(BrightnessEvent.class))) .thenReturn(automaticScreenBrightness); + when(automaticBrightnessController.getAutomaticScreenBrightnessBasedOnLastObservedLux( + any(BrightnessEvent.class))) + .thenReturn(automaticScreenBrightness); mAutomaticBrightnessStrategy.setAutomaticBrightnessController( automaticBrightnessController); assertEquals(automaticScreenBrightness, mAutomaticBrightnessStrategy.getAutomaticScreenBrightness( new BrightnessEvent(DISPLAY_ID)), 0.0f); + assertEquals(automaticScreenBrightness, + mAutomaticBrightnessStrategy.getAutomaticScreenBrightnessBasedOnLastObservedLux( + new BrightnessEvent(DISPLAY_ID)), 0.0f); } @Test diff --git a/services/tests/dreamservicetests/Android.bp b/services/tests/dreamservicetests/Android.bp index 5aa5d619854f..86b3a6cc2b35 100644 --- a/services/tests/dreamservicetests/Android.bp +++ b/services/tests/dreamservicetests/Android.bp @@ -18,6 +18,11 @@ android_test { "mockito-target-minus-junit4", "services.core", "mockingservicestests-utils-mockito", + "servicestests-utils", + ], + + defaults: [ + "modules-utils-testable-device-config-defaults", ], platform_apis: true, diff --git a/services/tests/dreamservicetests/AndroidManifest.xml b/services/tests/dreamservicetests/AndroidManifest.xml index f4b88d9c18e9..6092ef6f9427 100644 --- a/services/tests/dreamservicetests/AndroidManifest.xml +++ b/services/tests/dreamservicetests/AndroidManifest.xml @@ -21,6 +21,7 @@ Insert permissions here. eg: <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> --> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> <application android:debuggable="true" android:testOnly="true"> diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamManagerServiceMockingTest.java b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamManagerServiceMockingTest.java index 32d4e756d589..992b8534accc 100644 --- a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamManagerServiceMockingTest.java +++ b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamManagerServiceMockingTest.java @@ -36,13 +36,14 @@ import android.os.UserManager; import android.provider.Settings; import androidx.test.InstrumentationRegistry; -import androidx.test.filters.FlakyTest; -import com.android.server.LocalServices; +import com.android.internal.util.test.LocalServiceKeeperRule; import com.android.server.SystemService; +import com.android.server.testutils.TestHandler; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -65,23 +66,24 @@ public class DreamManagerServiceMockingTest { @Mock private UserManager mUserManagerMock; - private MockitoSession mMockitoSession; + @Rule + public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule(); - private static <T> void addLocalServiceMock(Class<T> clazz, T mock) { - LocalServices.removeServiceForTest(clazz); - LocalServices.addService(clazz, mock); - } + private TestHandler mTestHandler; + private MockitoSession mMockitoSession; @Before public void setUp() throws Exception { + mTestHandler = new TestHandler(/* callback= */ null); MockitoAnnotations.initMocks(this); - mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); mResourcesSpy = spy(mContextSpy.getResources()); when(mContextSpy.getResources()).thenReturn(mResourcesSpy); - addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock); - addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock); + mLocalServiceKeeperRule.overrideLocalService( + ActivityManagerInternal.class, mActivityManagerInternalMock); + mLocalServiceKeeperRule.overrideLocalService( + PowerManagerInternal.class, mPowerManagerInternalMock); when(mContextSpy.getSystemService(UserManager.class)).thenReturn(mUserManagerMock); mMockitoSession = mockitoSession() @@ -94,26 +96,20 @@ public class DreamManagerServiceMockingTest { @After public void tearDown() throws Exception { mMockitoSession.finishMocking(); - LocalServices.removeServiceForTest(ActivityManagerInternal.class); - LocalServices.removeServiceForTest(PowerManagerInternal.class); } private DreamManagerService createService() { - return new DreamManagerService(mContextSpy); + return new DreamManagerService(mContextSpy, mTestHandler); } @Test - @FlakyTest(bugId = 293443309) public void testSettingsQueryUserChange() { final DreamManagerService service = createService(); - final SystemService.TargetUser from = new SystemService.TargetUser(mock(UserInfo.class)); final SystemService.TargetUser to = new SystemService.TargetUser(mock(UserInfo.class)); - service.onUserSwitching(from, to); - verify(() -> Settings.Secure.getIntForUser(any(), eq(Settings.Secure.SCREENSAVER_ENABLED), anyInt(), diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java index dad36e787360..2366f56707fa 100644 --- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java @@ -30,6 +30,7 @@ import static org.mockito.Mockito.verifyZeroInteractions; import android.media.projection.MediaProjectionInfo; import android.media.projection.MediaProjectionManager; import android.os.Binder; +import android.os.Process; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; @@ -52,6 +53,8 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Set; + @SmallTest @RunWith(AndroidTestingRunner.class) @RequiresFlagsEnabled(FLAG_SENSITIVE_CONTENT_APP_PROTECTION) @@ -62,12 +65,14 @@ import org.mockito.MockitoAnnotations; public class SensitiveContentProtectionManagerServiceContentTest { private final PackageInfo mPackageInfo = new PackageInfo("test.package", 12345, new Binder()); + private final String mScreenRecorderPackage = "test.screen.recorder.package"; + private final String mExemptedScreenRecorderPackage = "test.exempted.screen.recorder.package"; private SensitiveContentProtectionManagerService mSensitiveContentProtectionManagerService; private MediaProjectionManager.Callback mMediaPorjectionCallback; @Mock private WindowManagerInternal mWindowManager; @Mock private MediaProjectionManager mProjectionManager; - @Mock private MediaProjectionInfo mMediaProjectionInfo; + private MediaProjectionInfo mMediaProjectionInfo; @Captor private ArgumentCaptor<MediaProjectionManager.Callback> mMediaProjectionCallbackCaptor; @@ -85,9 +90,22 @@ public class SensitiveContentProtectionManagerServiceContentTest { MockitoAnnotations.initMocks(this); mSensitiveContentProtectionManagerService = new SensitiveContentProtectionManagerService(mContext); - mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager); + mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager, + new ArraySet<>(Set.of(mExemptedScreenRecorderPackage))); verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any()); mMediaPorjectionCallback = mMediaProjectionCallbackCaptor.getValue(); + mMediaProjectionInfo = + new MediaProjectionInfo(mScreenRecorderPackage, Process.myUserHandle(), null); + } + + @Test + public void testExemptedRecorderPackageForScreenCapture() { + MediaProjectionInfo exemptedRecorderPackage = new MediaProjectionInfo( + mExemptedScreenRecorderPackage, Process.myUserHandle(), null); + mMediaPorjectionCallback.onStart(exemptedRecorderPackage); + mSensitiveContentProtectionManagerService.setSensitiveContentProtection( + mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), true); + verifyZeroInteractions(mWindowManager); } @Test diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java index 08050a9b30e0..e74fe296d0a5 100644 --- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java @@ -78,6 +78,8 @@ public class SensitiveContentProtectionManagerServiceNotificationTest { private static final String NOTIFICATION_PKG_1 = "com.android.server.notification.one"; private static final String NOTIFICATION_PKG_2 = "com.android.server.notification.two"; + private static final String EXEMPTED_SCREEN_RECORDER_PACKAGE = "test.screen.recorder.package"; + private static final int NOTIFICATION_UID_1 = 5; private static final int NOTIFICATION_UID_2 = 6; @@ -138,7 +140,8 @@ public class SensitiveContentProtectionManagerServiceNotificationTest { setupSensitiveNotification(); - mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager); + mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager, + new ArraySet<>(Set.of(EXEMPTED_SCREEN_RECORDER_PACKAGE))); // Obtain useful mMediaProjectionCallback verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any()); @@ -275,6 +278,16 @@ public class SensitiveContentProtectionManagerServiceNotificationTest { } @Test + public void mediaProjectionOnStart_verifyExemptedRecorderPackage() { + MediaProjectionInfo mediaProjectionInfo = mock(MediaProjectionInfo.class); + when(mediaProjectionInfo.getPackageName()).thenReturn(EXEMPTED_SCREEN_RECORDER_PACKAGE); + + mMediaProjectionCallbackCaptor.getValue().onStart(mediaProjectionInfo); + + verifyZeroInteractions(mWindowManager); + } + + @Test public void mediaProjectionOnStart_onProjectionStart_setWmBlockedPackages() { ArraySet<PackageInfo> expectedBlockedPackages = setupSensitiveNotification(); diff --git a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java index a8faa54fe9d6..ad68de84eace 100644 --- a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java @@ -196,6 +196,9 @@ public class BatterySaverStateMachineTest { when(mMockResources.getBoolean( com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled)) .thenReturn(false); + when(mMockResources.getBoolean( + com.android.internal.R.bool.config_batterySaverTurnedOffNotificationEnabled)) + .thenReturn(true); when(mMockResources.getInteger( com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold)) .thenReturn(80); diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java index d6e246fc7ee1..6e416857abbf 100644 --- a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java @@ -25,6 +25,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -42,6 +44,7 @@ import android.content.rollback.RollbackManager; import android.crashrecovery.flags.Flags; import android.os.Handler; import android.os.MessageQueue; +import android.os.SystemProperties; import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.runner.AndroidJUnit4; @@ -65,6 +68,7 @@ import org.mockito.quality.Strictness; import org.mockito.stubbing.Answer; import java.time.Duration; +import java.util.HashMap; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -90,7 +94,7 @@ public class RollbackPackageHealthObserverTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); - + private HashMap<String, String> mSystemSettingsMap; private MockitoSession mSession; private static final String APP_A = "com.package.a"; private static final String APP_B = "com.package.b"; @@ -99,6 +103,9 @@ public class RollbackPackageHealthObserverTest { private static final long VERSION_CODE_2 = 2L; private static final String LOG_TAG = "RollbackPackageHealthObserverTest"; + private static final String PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG = + "persist.device_config.configuration.disable_high_impact_rollback"; + private SystemConfig mSysConfig; @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); @@ -111,11 +118,34 @@ public class RollbackPackageHealthObserverTest { .initMocks(this) .strictness(Strictness.LENIENT) .spyStatic(PackageWatchdog.class) + .spyStatic(SystemProperties.class) .startMocking(); + mSystemSettingsMap = new HashMap<>(); // Mock PackageWatchdog doAnswer((Answer<PackageWatchdog>) invocationOnMock -> mMockPackageWatchdog) .when(() -> PackageWatchdog.getInstance(mMockContext)); + + // Mock SystemProperties setter and various getters + doAnswer((Answer<Void>) invocationOnMock -> { + String key = invocationOnMock.getArgument(0); + String value = invocationOnMock.getArgument(1); + + mSystemSettingsMap.put(key, value); + return null; + } + ).when(() -> SystemProperties.set(anyString(), anyString())); + + doAnswer((Answer<Boolean>) invocationOnMock -> { + String key = invocationOnMock.getArgument(0); + boolean defaultValue = invocationOnMock.getArgument(1); + + String storedValue = mSystemSettingsMap.get(key); + return storedValue == null ? defaultValue : Boolean.parseBoolean(storedValue); + } + ).when(() -> SystemProperties.getBoolean(anyString(), anyBoolean())); + + SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(false)); } @After @@ -609,6 +639,32 @@ public class RollbackPackageHealthObserverTest { observer.onBootLoop(1)); } + @Test + public void onBootLoop_impactLevelHighDisableHighImpactRollback_onePackage() + throws PackageManager.NameNotFoundException { + mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); + SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(true)); + VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); + VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); + PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo, + null, null, false, false, + null); + RollbackInfo rollbackInfo1 = new RollbackInfo(1, List.of(packageRollbackInfo), + false, null, 111, + PackageManager.ROLLBACK_USER_IMPACT_HIGH); + RollbackPackageHealthObserver observer = + spy(new RollbackPackageHealthObserver(mMockContext, mApexManager)); + + when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager); + // Make the rollbacks available + when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(rollbackInfo1)); + when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); + when(mMockPackageManager.getModuleInfo(any(), eq(0))).thenReturn(null); + + assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_0, + observer.onBootLoop(1)); + } + /** * When the rollback impact level is manual only return user impact level 0. (User impact level * 0 is ignored by package watchdog) @@ -924,6 +980,50 @@ public class RollbackPackageHealthObserverTest { assertThat(argument.getAllValues()).isEqualTo(List.of(rollbackId2)); } + /** + * Don't roll back if kill switch is enabled. + */ + @Test + public void executeBootLoopMitigation_impactLevelHighKillSwitchTrue_rollbackHigh() + throws PackageManager.NameNotFoundException { + mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION); + SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(true)); + int rollbackId1 = 1; + VersionedPackage appBFrom = new VersionedPackage(APP_B, VERSION_CODE_2); + VersionedPackage appBTo = new VersionedPackage(APP_B, VERSION_CODE); + PackageRollbackInfo packageRollbackInfoB = new PackageRollbackInfo(appBFrom, appBTo, + null, null , false, false, + null); + RollbackInfo rollbackInfo1 = new RollbackInfo(rollbackId1, List.of(packageRollbackInfoB), + false, null, 111, + PackageManager.ROLLBACK_USER_IMPACT_HIGH); + int rollbackId2 = 2; + VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2); + VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE); + PackageRollbackInfo packageRollbackInfoA = new PackageRollbackInfo(appAFrom, appATo, + null, null , false, false, + null); + RollbackInfo rollbackInfo2 = new RollbackInfo(rollbackId2, List.of(packageRollbackInfoA), + false, null, 111, + PackageManager.ROLLBACK_USER_IMPACT_HIGH); + RollbackPackageHealthObserver observer = + spy(new RollbackPackageHealthObserver(mMockContext, mApexManager)); + ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class); + + when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager); + // Make the rollbacks available + when(mRollbackManager.getAvailableRollbacks()).thenReturn( + List.of(rollbackInfo1, rollbackInfo2)); + when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); + when(mMockPackageManager.getModuleInfo(any(), eq(0))).thenReturn(null); + + observer.executeBootLoopMitigation(1); + waitForIdleHandler(observer.getHandler(), Duration.ofSeconds(10)); + + verify(mRollbackManager, never()).commitRollback( + argument.capture(), any(), any()); + } + private void waitForIdleHandler(Handler handler, Duration timeout) { final MessageQueue queue = handler.getLooper().getQueue(); final CountDownLatch latch = new CountDownLatch(1); diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java index 548fae7a0b01..a1101cd0f0bc 100644 --- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java +++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java @@ -578,45 +578,136 @@ public class BatteryStatsImplTest { // First wakelock, acquired once, not currently held mMockClock.realtime = 1000; - mBatteryStatsImpl.noteStartWakeLocked(10100, 100, null, "wakeLock1", null, - BatteryStats.WAKE_TYPE_PARTIAL, false); + mBatteryStatsImpl.noteStartWakeLocked( + 10100, 100, null, "wakeLock1", null, BatteryStats.WAKE_TYPE_PARTIAL, false); mMockClock.realtime = 3000; - mBatteryStatsImpl.noteStopWakeLocked(10100, 100, null, "wakeLock1", null, - BatteryStats.WAKE_TYPE_PARTIAL); + mBatteryStatsImpl.noteStopWakeLocked( + 10100, 100, null, "wakeLock1", null, BatteryStats.WAKE_TYPE_PARTIAL); // Second wakelock, acquired twice, still held mMockClock.realtime = 4000; - mBatteryStatsImpl.noteStartWakeLocked(10200, 101, null, "wakeLock2", null, - BatteryStats.WAKE_TYPE_PARTIAL, false); + mBatteryStatsImpl.noteStartWakeLocked( + 10200, 101, null, "wakeLock2", null, BatteryStats.WAKE_TYPE_PARTIAL, false); mMockClock.realtime = 5000; - mBatteryStatsImpl.noteStopWakeLocked(10200, 101, null, "wakeLock2", null, - BatteryStats.WAKE_TYPE_PARTIAL); + mBatteryStatsImpl.noteStopWakeLocked( + 10200, 101, null, "wakeLock2", null, BatteryStats.WAKE_TYPE_PARTIAL); mMockClock.realtime = 6000; - mBatteryStatsImpl.noteStartWakeLocked(10200, 101, null, "wakeLock2", null, - BatteryStats.WAKE_TYPE_PARTIAL, false); + mBatteryStatsImpl.noteStartWakeLocked( + 10200, 101, null, "wakeLock2", null, BatteryStats.WAKE_TYPE_PARTIAL, false); - mMockClock.realtime = 9000; - - List<WakeLockStats.WakeLock> wakeLockStats = - mBatteryStatsImpl.getWakeLockStats().getWakeLocks(); - assertThat(wakeLockStats).hasSize(2); + // Third and fourth wakelocks, overlapped with each other. + mMockClock.realtime = 7000; + mBatteryStatsImpl.noteStartWakeLocked( + 10300, 102, null, "wakeLock3", null, BatteryStats.WAKE_TYPE_PARTIAL, false); - WakeLockStats.WakeLock wakeLock1 = wakeLockStats.stream() - .filter(wl -> wl.uid == 10100 && wl.name.equals("wakeLock1")).findFirst().get(); + mMockClock.realtime = 8000; + mBatteryStatsImpl.noteStartWakeLocked( + 10400, 103, null, "wakeLock4", null, BatteryStats.WAKE_TYPE_PARTIAL, false); - assertThat(wakeLock1.timesAcquired).isEqualTo(1); - assertThat(wakeLock1.timeHeldMs).isEqualTo(0); // Not currently held - assertThat(wakeLock1.totalTimeHeldMs).isEqualTo(2000); // 3000-1000 + mMockClock.realtime = 9000; + mBatteryStatsImpl.noteStopWakeLocked( + 10400, 103, null, "wakeLock4", null, BatteryStats.WAKE_TYPE_PARTIAL); + + mMockClock.realtime = 10000; + mBatteryStatsImpl.noteStartWakeLocked( + 10400, 104, null, "wakeLock5", null, BatteryStats.WAKE_TYPE_PARTIAL, false); + + mMockClock.realtime = 11000; + mBatteryStatsImpl.noteStopWakeLocked( + 10400, 104, null, "wakeLock5", null, BatteryStats.WAKE_TYPE_PARTIAL); + + mMockClock.realtime = 12000; + mBatteryStatsImpl.noteStopWakeLocked( + 10300, 102, null, "wakeLock3", null, BatteryStats.WAKE_TYPE_PARTIAL); + + mMockClock.realtime = 13000; + + // Verify un-aggregated wakelocks. + WakeLockStats wakeLockStats = mBatteryStatsImpl.getWakeLockStats(); + List<WakeLockStats.WakeLock> wakeLockList = wakeLockStats.getWakeLocks(); + assertThat(wakeLockList).hasSize(4); + + WakeLockStats.WakeLock wakeLock1 = getWakeLockFromList(wakeLockList, 10100, "wakeLock1"); + assertThat(wakeLock1.isAggregated).isFalse(); + assertThat(wakeLock1.totalWakeLockData.timesAcquired).isEqualTo(1); + assertThat(wakeLock1.totalWakeLockData.timeHeldMs).isEqualTo(0); // Not currently held + assertThat(wakeLock1.totalWakeLockData.totalTimeHeldMs).isEqualTo(2000); // 3000-1000 + + WakeLockStats.WakeLock wakeLock3 = getWakeLockFromList(wakeLockList, 10300, "wakeLock3"); + assertThat(wakeLock3.isAggregated).isFalse(); + assertThat(wakeLock3.totalWakeLockData.timesAcquired).isEqualTo(1); + assertThat(wakeLock3.totalWakeLockData.timeHeldMs).isEqualTo(0); // Not currently held + // (8000-7000)/2 + (9000-8000)/3 + (10000-9000)/2 + (11000-10000)/3 + (12000-11000)/2 + assertThat(wakeLock3.totalWakeLockData.totalTimeHeldMs).isEqualTo(2166); + + WakeLockStats.WakeLock wakeLock4 = getWakeLockFromList(wakeLockList, 10400, "wakeLock4"); + assertThat(wakeLock4.isAggregated).isFalse(); + assertThat(wakeLock4.totalWakeLockData.timesAcquired).isEqualTo(1); + assertThat(wakeLock4.totalWakeLockData.timeHeldMs).isEqualTo(0); // Not currently held + assertThat(wakeLock4.totalWakeLockData.totalTimeHeldMs).isEqualTo(333); // (9000-8000)/3 + + WakeLockStats.WakeLock wakeLock5 = getWakeLockFromList(wakeLockList, 10400, "wakeLock5"); + assertThat(wakeLock5.isAggregated).isFalse(); + assertThat(wakeLock5.totalWakeLockData.timesAcquired).isEqualTo(1); + assertThat(wakeLock5.totalWakeLockData.timeHeldMs).isEqualTo(0); // Not currently held + assertThat(wakeLock5.totalWakeLockData.totalTimeHeldMs).isEqualTo(333); // (11000-10000)/3 + + // Verify aggregated wakelocks. + List<WakeLockStats.WakeLock> aggregatedWakeLockList = + wakeLockStats.getAggregatedWakeLocks(); + assertThat(aggregatedWakeLockList).hasSize(4); + + WakeLockStats.WakeLock aggregatedWakeLock1 = + getAggregatedWakeLockFromList(aggregatedWakeLockList, 10100); + assertThat(aggregatedWakeLock1.isAggregated).isTrue(); + assertThat(aggregatedWakeLock1.totalWakeLockData.timesAcquired).isEqualTo(1); + // Not currently held + assertThat(aggregatedWakeLock1.totalWakeLockData.timeHeldMs).isEqualTo(0); + // 3000-1000 + assertThat(aggregatedWakeLock1.totalWakeLockData.totalTimeHeldMs).isEqualTo(2000); + + WakeLockStats.WakeLock aggregatedWakeLock2 = + getAggregatedWakeLockFromList(aggregatedWakeLockList, 10200); + assertThat(aggregatedWakeLock2.isAggregated).isTrue(); + assertThat(aggregatedWakeLock2.totalWakeLockData.timesAcquired).isEqualTo(2); + assertThat(aggregatedWakeLock2.totalWakeLockData.timeHeldMs).isEqualTo(7000); // 13000-6000 + // (5000-4000) + (13000-6000) + assertThat(aggregatedWakeLock2.totalWakeLockData.totalTimeHeldMs) + .isEqualTo(8000); + + WakeLockStats.WakeLock aggregatedWakeLock3 = + getAggregatedWakeLockFromList(aggregatedWakeLockList, 10300); + assertThat(aggregatedWakeLock3.isAggregated).isTrue(); + assertThat(aggregatedWakeLock3.totalWakeLockData.timesAcquired).isEqualTo(1); + // Not currently held + assertThat(aggregatedWakeLock3.totalWakeLockData.timeHeldMs).isEqualTo(0); + // 12000-7000 + assertThat(aggregatedWakeLock3.totalWakeLockData.totalTimeHeldMs).isEqualTo(5000); + + WakeLockStats.WakeLock aggregatedWakeLock4 = + getAggregatedWakeLockFromList(aggregatedWakeLockList, 10400); + assertThat(aggregatedWakeLock4.isAggregated).isTrue(); + assertThat(aggregatedWakeLock4.totalWakeLockData.timesAcquired).isEqualTo(2); + // Not currently held + assertThat(aggregatedWakeLock4.totalWakeLockData.timeHeldMs).isEqualTo(0); + assertThat(aggregatedWakeLock4.totalWakeLockData.totalTimeHeldMs) + .isEqualTo(2000); // (9000-8000) + (11000-10000) + } - WakeLockStats.WakeLock wakeLock2 = wakeLockStats.stream() - .filter(wl -> wl.uid == 10200 && wl.name.equals("wakeLock2")).findFirst().get(); + private WakeLockStats.WakeLock getAggregatedWakeLockFromList( + List<WakeLockStats.WakeLock> wakeLockList, final int uid) { + return getWakeLockFromList(wakeLockList, uid, WakeLockStats.WakeLock.NAME_AGGREGATED); + } - assertThat(wakeLock2.timesAcquired).isEqualTo(2); - assertThat(wakeLock2.timeHeldMs).isEqualTo(3000); // 9000-6000 - assertThat(wakeLock2.totalTimeHeldMs).isEqualTo(4000); // (5000-4000) + (9000-6000) + private WakeLockStats.WakeLock getWakeLockFromList( + List<WakeLockStats.WakeLock> wakeLockList, final int uid, final String name) { + return wakeLockList.stream() + .filter(wl -> wl.uid == uid && wl.name.equals(name)) + .findFirst() + .get(); } @Test diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index 3743483377b5..37967fa86b0f 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -85,6 +85,7 @@ android_test { "ravenwood-junit", "net_flags_lib", "CtsVirtualDeviceCommonLib", + "com_android_server_accessibility_flags_lib", ], libs: [ diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt index 5c8c6bb69ef8..e6c94c51d1b1 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt @@ -25,6 +25,7 @@ import android.view.Display.DEFAULT_DISPLAY import android.view.DisplayAdjustments import android.view.DisplayInfo import android.view.IInputFilterHost +import android.view.InputDevice.SOURCE_JOYSTICK import android.view.InputDevice.SOURCE_STYLUS import android.view.InputDevice.SOURCE_TOUCHSCREEN import android.view.InputEvent @@ -130,6 +131,8 @@ class AccessibilityInputFilterInputTest { private val fromTouchScreen = allOf(withDeviceId(touchDeviceId), withSource(SOURCE_TOUCHSCREEN)) private val stylusDeviceId = 2 private val fromStylus = allOf(withDeviceId(stylusDeviceId), withSource(STYLUS_SOURCE)) + private val joystickDeviceId = 3 + private val fromJoystick = allOf(withDeviceId(joystickDeviceId), withSource(SOURCE_JOYSTICK)) @Before fun setUp() { @@ -457,6 +460,23 @@ class AccessibilityInputFilterInputTest { verifier.assertNoEvents() } + /** + * Send some joystick events and ensure they pass through normally. + */ + @Test + fun testJoystickEvents() { + enableFeatures(ALL_A11Y_FEATURES) + + sendJoystickEvent() + verifier.assertReceivedMotion(fromJoystick) + + sendJoystickEvent() + verifier.assertReceivedMotion(fromJoystick) + + sendJoystickEvent() + verifier.assertReceivedMotion(fromJoystick) + } + private fun createStubDisplay(displayId: Int, displayInfo: DisplayInfo): Display { val display = Display(DisplayManagerGlobal.getInstance(), displayId, displayInfo, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS) @@ -477,6 +497,11 @@ class AccessibilityInputFilterInputTest { send(createMotionEvent(action, downTime, eventTime, STYLUS_SOURCE, stylusDeviceId)) } + private fun sendJoystickEvent() { + val time = SystemClock.uptimeMillis() + send(createMotionEvent(ACTION_MOVE, time, time, SOURCE_JOYSTICK, joystickDeviceId)) + } + private fun send(event: InputEvent) { // We need to make a copy of the event before sending it to the filter, because the filter // will recycle it, but the caller of this function might want to still be able to use diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java index 89d146da1b75..8717a0500e57 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java @@ -47,6 +47,9 @@ import android.os.IBinder; import android.os.LocaleList; import android.os.RemoteException; import android.os.UserHandle; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.SparseArray; import android.view.Display; import android.view.IWindow; @@ -67,6 +70,7 @@ import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; @@ -77,9 +81,16 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +// This test verifies deprecated codepath. Probably changing this file means +// AccessibilityWindowManagerWithAccessibilityWindowTest also needs to be updated. +// LINT.IfChange + /** - * Tests for the AccessibilityWindowManager + * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y enabled. + * TODO(b/322444245): Merge with AccessibilityWindowManagerWithAccessibilityWindowTest + * after completing the flag migration. */ +@RequiresFlagsDisabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y) public class AccessibilityWindowManagerTest { private static final String PACKAGE_NAME = "com.android.server.accessibility"; private static final boolean FORCE_SEND = true; @@ -132,6 +143,9 @@ public class AccessibilityWindowManagerTest { @Mock private IBinder mMockEmbeddedToken; @Mock private IBinder mMockInvalidToken; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Before public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); @@ -1227,3 +1241,4 @@ public class AccessibilityWindowManagerTest { } } } +// LINT.ThenChange(/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java) diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java new file mode 100644 index 000000000000..4db27d272f8e --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java @@ -0,0 +1,1247 @@ +/* + * Copyright (C) 2019 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.accessibility; + +import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT; +import static com.android.server.accessibility.AccessibilityWindowManagerTest.DisplayIdMatcher.displayId; +import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowChangesMatcher.a11yWindowChanges; +import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowIdMatcher.a11yWindowId; + +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; + +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.annotation.Nullable; +import android.graphics.Region; +import android.os.IBinder; +import android.os.LocaleList; +import android.os.RemoteException; +import android.os.UserHandle; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; +import android.util.SparseArray; +import android.view.Display; +import android.view.IWindow; +import android.view.WindowInfo; +import android.view.WindowManager; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityWindowAttributes; +import android.view.accessibility.AccessibilityWindowInfo; +import android.view.accessibility.IAccessibilityInteractionConnection; + +import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection; +import com.android.server.accessibility.test.MessageCapturingHandler; +import com.android.server.wm.WindowManagerInternal; +import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback; + +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y + * TODO(b/322444245): Merge with AccessibilityWindowManagerTest + * after completing the flag migration. + */ +@RequiresFlagsEnabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y) +public class AccessibilityWindowManagerWithAccessibilityWindowTest { + private static final String PACKAGE_NAME = "com.android.server.accessibility"; + private static final boolean FORCE_SEND = true; + private static final boolean SEND_ON_WINDOW_CHANGES = false; + private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM; + private static final int USER_PROFILE = 11; + private static final int USER_PROFILE_PARENT = 1; + private static final int SECONDARY_DISPLAY_ID = Display.DEFAULT_DISPLAY + 1; + private static final int NUM_GLOBAL_WINDOWS = 4; + private static final int NUM_APP_WINDOWS = 4; + private static final int NUM_OF_WINDOWS = (NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS); + private static final int DEFAULT_FOCUSED_INDEX = 1; + private static final int SCREEN_WIDTH = 1080; + private static final int SCREEN_HEIGHT = 1920; + private static final int INVALID_ID = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; + private static final int HOST_WINDOW_ID = 10; + private static final int EMBEDDED_WINDOW_ID = 11; + private static final int OTHER_WINDOW_ID = 12; + + private AccessibilityWindowManager mA11yWindowManager; + // Window manager will support multiple focused window if config_perDisplayFocusEnabled is true, + // i.e., each display would have its current focused window, and one of all focused windows + // would be top focused window. Otherwise, window manager only supports one focused window + // at all displays, and that focused window would be top focused window. + private boolean mSupportPerDisplayFocus = false; + private int mTopFocusedDisplayId = Display.INVALID_DISPLAY; + private IBinder mTopFocusedWindowToken = null; + + // List of window token, mapping from windowId -> window token. + private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>(); + // List of window info lists, mapping from displayId -> window info lists. + private final SparseArray<ArrayList<WindowInfo>> mWindowInfos = + new SparseArray<>(); + // List of callback, mapping from displayId -> callback. + private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows = + new SparseArray<>(); + // List of display ID. + private final ArrayList<Integer> mExpectedDisplayList = new ArrayList<>(Arrays.asList( + Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID)); + + private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null); + + @Mock + private WindowManagerInternal mMockWindowManagerInternal; + @Mock + private AccessibilityWindowManager.AccessibilityEventSender mMockA11yEventSender; + @Mock + private AccessibilitySecurityPolicy mMockA11ySecurityPolicy; + @Mock + private AccessibilitySecurityPolicy.AccessibilityUserManager mMockA11yUserManager; + @Mock + private AccessibilityTraceManager mMockA11yTraceManager; + + @Mock + private IBinder mMockHostToken; + @Mock + private IBinder mMockEmbeddedToken; + @Mock + private IBinder mMockInvalidToken; + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + + @Before + public void setUp() throws RemoteException { + MockitoAnnotations.initMocks(this); + when(mMockA11yUserManager.getCurrentUserIdLocked()).thenReturn(USER_SYSTEM_ID); + when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked( + USER_PROFILE)).thenReturn(USER_PROFILE_PARENT); + when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked( + USER_SYSTEM_ID)).thenReturn(USER_SYSTEM_ID); + when(mMockA11ySecurityPolicy.resolveValidReportedPackageLocked( + anyString(), anyInt(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME); + + doAnswer((invocation) -> { + onWindowsForAccessibilityChanged(invocation.getArgument(0), false); + return null; + }).when(mMockWindowManagerInternal).computeWindowsForAccessibility(anyInt()); + + mA11yWindowManager = new AccessibilityWindowManager(new Object(), mHandler, + mMockWindowManagerInternal, + mMockA11yEventSender, + mMockA11ySecurityPolicy, + mMockA11yUserManager, + mMockA11yTraceManager); + // Starts tracking window of default display and sets the default display + // as top focused display before each testing starts. + startTrackingPerDisplay(Display.DEFAULT_DISPLAY); + + // AccessibilityEventSender is invoked during onWindowsForAccessibilityChanged. + // Resets it for mockito verify of further test case. + Mockito.reset(mMockA11yEventSender); + + registerLeashedTokenAndWindowId(); + } + + @After + public void tearDown() { + mHandler.removeAllMessages(); + } + + @Test + public void startTrackingWindows_shouldEnableWindowManagerCallback() { + // AccessibilityWindowManager#startTrackingWindows already invoked in setup. + assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)); + final WindowsForAccessibilityCallback callbacks = + mCallbackOfWindows.get(Display.DEFAULT_DISPLAY); + verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback( + eq(Display.DEFAULT_DISPLAY), eq(callbacks)); + } + + @Test + public void stopTrackingWindows_shouldDisableWindowManagerCallback() { + assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)); + Mockito.reset(mMockWindowManagerInternal); + + mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY); + assertFalse(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)); + verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback( + eq(Display.DEFAULT_DISPLAY), isNull()); + + } + + @Test + public void stopTrackingWindows_shouldClearWindows() { + assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY)); + final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); + + mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY); + assertNull(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY)); + assertEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT), + AccessibilityWindowInfo.UNDEFINED_WINDOW_ID); + assertEquals(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), + activeWindowId); + } + + @Test + public void stopTrackingWindows_onNonTopFocusedDisplay_shouldNotResetTopFocusWindow() + throws RemoteException { + // At setup, the default display sets be the top focused display and + // its current focused window sets be the top focused window. + // Starts tracking window of second display. + startTrackingPerDisplay(SECONDARY_DISPLAY_ID); + assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID)); + // Stops tracking windows of second display. + mA11yWindowManager.stopTrackingWindows(SECONDARY_DISPLAY_ID); + assertNotEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT), + AccessibilityWindowInfo.UNDEFINED_WINDOW_ID); + } + + @Test + public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() { + final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); + WindowInfo focusedWindowInfo = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX); + assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked( + USER_SYSTEM_ID, focusedWindowInfo.token)); + + focusedWindowInfo.focused = false; + focusedWindowInfo = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1); + focusedWindowInfo.focused = true; + + mA11yWindowManager.onTouchInteractionStart(); + setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + + assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID)); + } + + @Test + public void + onWindowsChanged_focusChangeOnNonTopFocusedDisplay_perDisplayFocusOn_notChangeWindow() + throws RemoteException { + // At setup, the default display sets be the top focused display and + // its current focused window sets be the top focused window. + // Sets supporting multiple focused window, i.e., config_perDisplayFocusEnabled is true. + mSupportPerDisplayFocus = true; + // Starts tracking window of second display. + startTrackingPerDisplay(SECONDARY_DISPLAY_ID); + // Gets the active window. + final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); + // Gets the top focused window. + final int topFocusedWindowId = + mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT); + // Changes the current focused window at second display. + changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID, + DEFAULT_FOCUSED_INDEX + 1, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX); + + onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES); + // The active window should not be changed. + assertEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID)); + // The top focused window should not be changed. + assertEquals(topFocusedWindowId, + mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT)); + } + + @Test + public void + onWindowChange_focusChangeToNonTopFocusedDisplay_perDisplayFocusOff_shouldChangeWindow() + throws RemoteException { + // At setup, the default display sets be the top focused display and + // its current focused window sets be the top focused window. + // Sets not supporting multiple focused window, i.e., config_perDisplayFocusEnabled is + // false. + mSupportPerDisplayFocus = false; + // Starts tracking window of second display. + startTrackingPerDisplay(SECONDARY_DISPLAY_ID); + // Gets the active window. + final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); + // Gets the top focused window. + final int topFocusedWindowId = + mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT); + // Changes the current focused window from default display to second display. + changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID, + DEFAULT_FOCUSED_INDEX, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX); + + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES); + // The active window should be changed. + assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID)); + // The top focused window should be changed. + assertNotEquals(topFocusedWindowId, + mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT)); + } + + @Test + public void onWindowsChanged_shouldReportCorrectLayer() { + // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup. + List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); + for (int i = 0; i < a11yWindows.size(); i++) { + final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i); + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i); + assertThat(mWindowInfos.get(Display.DEFAULT_DISPLAY).size() - windowInfo.layer - 1, + is(a11yWindow.getLayer())); + } + } + + @Test + public void onWindowsChanged_shouldReportCorrectOrder() { + // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup. + List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); + for (int i = 0; i < a11yWindows.size(); i++) { + final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i); + final IBinder windowToken = mA11yWindowManager + .getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId()); + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i); + assertThat(windowToken, is(windowInfo.token)); + } + } + + @Test + public void onWindowsChangedAndForceSend_shouldUpdateWindows() { + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); + final int correctLayer = + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer(); + windowInfo.layer += 1; + + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND); + assertNotEquals(correctLayer, + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer()); + } + + @Test + public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() { + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); + final int correctLayer = + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer(); + windowInfo.layer += 1; + + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + assertEquals(correctLayer, + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer()); + } + + @Test + public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows() + throws RemoteException { + final AccessibilityWindowInfo oldWindow = + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0); + final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, + true, USER_SYSTEM_ID); + final WindowInfo windowInfo = WindowInfo.obtain(); + windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION; + windowInfo.token = token.asBinder(); + windowInfo.layer = 0; + windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + mWindowInfos.get(Display.DEFAULT_DISPLAY).set(0, windowInfo); + + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + assertNotEquals(oldWindow, + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0)); + } + + @Test + public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() { + final WindowInfo focusedWindowInfo = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX); + final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); + focusedWindowInfo.focused = false; + windowInfo.focused = true; + + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + assertTrue(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0) + .isFocused()); + } + + @Test + public void removeAccessibilityInteractionConnection_byWindowToken_shouldRemoved() { + for (int i = 0; i < NUM_OF_WINDOWS; i++) { + final int windowId = mA11yWindowTokens.keyAt(i); + final IWindow windowToken = mA11yWindowTokens.valueAt(i); + assertNotNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId)); + + mA11yWindowManager.removeAccessibilityInteractionConnection(windowToken); + assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId)); + } + } + + @Test + public void remoteAccessibilityConnection_binderDied_shouldRemoveConnection() { + for (int i = 0; i < NUM_OF_WINDOWS; i++) { + final int windowId = mA11yWindowTokens.keyAt(i); + final RemoteAccessibilityConnection remoteA11yConnection = + mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId); + assertNotNull(remoteA11yConnection); + + remoteA11yConnection.binderDied(); + assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId)); + } + } + + @Test + public void getWindowTokenForUserAndWindowId_shouldNotNull() { + final List<AccessibilityWindowInfo> windows = + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); + for (int i = 0; i < windows.size(); i++) { + final int windowId = windows.get(i).getId(); + + assertNotNull(mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked( + USER_SYSTEM_ID, windowId)); + } + } + + @Test + public void findWindowId() { + final List<AccessibilityWindowInfo> windows = + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); + for (int i = 0; i < windows.size(); i++) { + final int windowId = windows.get(i).getId(); + final IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked( + USER_SYSTEM_ID, windowId); + + assertEquals(mA11yWindowManager.findWindowIdLocked( + USER_SYSTEM_ID, windowToken), windowId); + } + } + + @Test + public void resolveParentWindowId_windowIsNotEmbedded_shouldReturnGivenId() + throws RemoteException { + final int windowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, false, + Mockito.mock(IBinder.class), USER_SYSTEM_ID); + assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId)); + } + + @Test + public void resolveParentWindowId_windowIsNotRegistered_shouldReturnGivenId() { + final int windowId = -1; + assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId)); + } + + @Test + public void resolveParentWindowId_windowIsAssociated_shouldReturnParentWindowId() + throws RemoteException { + final IBinder mockHostToken = Mockito.mock(IBinder.class); + final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class); + final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, + false, mockHostToken, USER_SYSTEM_ID); + final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, + false, mockEmbeddedToken, USER_SYSTEM_ID); + + mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken); + + final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked( + embeddedWindowId); + assertEquals(hostWindowId, resolvedWindowId); + } + + @Test + public void resolveParentWindowId_windowIsDisassociated_shouldReturnGivenId() + throws RemoteException { + final IBinder mockHostToken = Mockito.mock(IBinder.class); + final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class); + final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, + false, mockHostToken, USER_SYSTEM_ID); + final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, + false, mockEmbeddedToken, USER_SYSTEM_ID); + + mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken); + mA11yWindowManager.disassociateEmbeddedHierarchyLocked(mockEmbeddedToken); + + final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked( + embeddedWindowId); + assertNotEquals(hostWindowId, resolvedWindowId); + assertEquals(embeddedWindowId, resolvedWindowId); + } + + @Test + public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() { + // Updates top 2 z-order WindowInfo are whole visible. + WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); + windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2); + windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1); + windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2, + SCREEN_WIDTH, SCREEN_HEIGHT); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + + final List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); + final Region outBounds = new Region(); + int windowId = a11yWindows.get(0).getId(); + + mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds); + assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH)); + assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2)); + + windowId = a11yWindows.get(1).getId(); + + mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds); + assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH)); + assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2)); + } + + @Test + public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() { + // Updates z-order #1 WindowInfo is half visible. + WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); + windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2); + + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + final List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); + final Region outBounds = new Region(); + int windowId = a11yWindows.get(1).getId(); + + mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds); + assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH)); + assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2)); + } + + @Test + public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() { + // Since z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible. + final List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); + final Region outBounds = new Region(); + int windowId = a11yWindows.get(1).getId(); + + mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds); + assertTrue(outBounds.getBounds().isEmpty()); + } + + @Test + public void computePartialInteractiveRegionForWindow_partialVisible_returnVisibleRegion() { + // Updates z-order #0 WindowInfo to have two interact-able areas. + Region region = new Region(0, 0, SCREEN_WIDTH, 200); + region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION); + WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0); + windowInfo.regionInScreen.set(region); + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + + final List<AccessibilityWindowInfo> a11yWindows = + mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY); + final Region outBounds = new Region(); + int windowId = a11yWindows.get(1).getId(); + + mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds); + assertFalse(outBounds.getBounds().isEmpty()); + assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH)); + assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT - 400)); + } + + @Test + public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() { + final IBinder eventWindowToken = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1).token; + final int eventWindowId = mA11yWindowManager.findWindowIdLocked( + USER_SYSTEM_ID, eventWindowToken); + when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates()) + .thenReturn(eventWindowToken); + + final int noUse = 0; + mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY); + mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, + eventWindowId, + noUse, + AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, + noUse); + assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId)); + assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT), + is(eventWindowId)); + } + + @Test + public void updateActiveAndA11yFocusedWindow_hoverEvent_touchInteract_shouldSetActiveWindow() { + final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX + 1); + final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); + assertThat(currentActiveWindowId, is(not(eventWindowId))); + + final int noUse = 0; + mA11yWindowManager.onTouchInteractionStart(); + mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, + eventWindowId, + noUse, + AccessibilityEvent.TYPE_VIEW_HOVER_ENTER, + noUse); + assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId)); + final ArgumentCaptor<AccessibilityEvent> captor = + ArgumentCaptor.forClass(AccessibilityEvent.class); + verify(mMockA11yEventSender, times(2)) + .sendAccessibilityEventForCurrentUserLocked(captor.capture()); + assertThat(captor.getAllValues().get(0), + allOf(displayId(Display.DEFAULT_DISPLAY), + a11yWindowId(currentActiveWindowId), + a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE))); + assertThat(captor.getAllValues().get(1), + allOf(displayId(Display.DEFAULT_DISPLAY), + a11yWindowId(eventWindowId), + a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE))); + } + + @Test + public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_shouldUpdateA11yFocus() { + final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX); + final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId( + AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); + assertThat(currentA11yFocusedWindowId, is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)); + + final int noUse = 0; + mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, + eventWindowId, + AccessibilityNodeInfo.ROOT_NODE_ID, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, + noUse); + assertThat(mA11yWindowManager.getFocusedWindowId( + AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId)); + final ArgumentCaptor<AccessibilityEvent> captor = + ArgumentCaptor.forClass(AccessibilityEvent.class); + verify(mMockA11yEventSender, times(1)) + .sendAccessibilityEventForCurrentUserLocked(captor.capture()); + assertThat(captor.getAllValues().get(0), + allOf(displayId(Display.DEFAULT_DISPLAY), + a11yWindowId(eventWindowId), + a11yWindowChanges( + AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED))); + } + + @Test + public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_defaultToSecondary() + throws RemoteException { + runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest( + Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID); + } + + @Test + public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_SecondaryToDefault() + throws RemoteException { + runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest( + SECONDARY_DISPLAY_ID, Display.DEFAULT_DISPLAY); + } + + private void runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest( + int initialDisplayId, int eventDisplayId) throws RemoteException { + startTrackingPerDisplay(SECONDARY_DISPLAY_ID); + final int initialWindowId = getWindowIdFromWindowInfosForDisplay( + initialDisplayId, DEFAULT_FOCUSED_INDEX); + final int noUse = 0; + mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, + initialWindowId, + AccessibilityNodeInfo.ROOT_NODE_ID, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, + noUse); + assertThat(mA11yWindowManager.getFocusedWindowId( + AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(initialWindowId)); + Mockito.reset(mMockA11yEventSender); + + final int eventWindowId = getWindowIdFromWindowInfosForDisplay( + eventDisplayId, DEFAULT_FOCUSED_INDEX); + mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, + eventWindowId, + AccessibilityNodeInfo.ROOT_NODE_ID, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, + noUse); + assertThat(mA11yWindowManager.getFocusedWindowId( + AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId)); + final ArgumentCaptor<AccessibilityEvent> captor = + ArgumentCaptor.forClass(AccessibilityEvent.class); + verify(mMockA11yEventSender, times(2)) + .sendAccessibilityEventForCurrentUserLocked(captor.capture()); + assertThat(captor.getAllValues().get(0), + allOf(displayId(initialDisplayId), + a11yWindowId(initialWindowId), + a11yWindowChanges( + AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED))); + assertThat(captor.getAllValues().get(1), + allOf(displayId(eventDisplayId), + a11yWindowId(eventWindowId), + a11yWindowChanges( + AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED))); + } + + @Test + public void updateActiveAndA11yFocusedWindow_clearA11yFocusEvent_shouldClearA11yFocus() { + final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX); + final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId( + AccessibilityNodeInfo.FOCUS_ACCESSIBILITY); + assertThat(currentA11yFocusedWindowId, is(not(eventWindowId))); + + final int noUse = 0; + mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, + eventWindowId, + AccessibilityNodeInfo.ROOT_NODE_ID, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, + noUse); + assertThat(mA11yWindowManager.getFocusedWindowId( + AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId)); + mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, + eventWindowId, + AccessibilityNodeInfo.ROOT_NODE_ID, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED, + noUse); + assertThat(mA11yWindowManager.getFocusedWindowId( + AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), + is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)); + } + + @Test + public void onTouchInteractionEnd_shouldRollbackActiveWindow() { + final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX + 1); + final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID); + assertThat(currentActiveWindowId, is(not(eventWindowId))); + + final int noUse = 0; + mA11yWindowManager.onTouchInteractionStart(); + mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, + eventWindowId, + noUse, + AccessibilityEvent.TYPE_VIEW_HOVER_ENTER, + noUse); + assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId)); + // AccessibilityEventSender is invoked after active window changed. Reset it. + Mockito.reset(mMockA11yEventSender); + + mA11yWindowManager.onTouchInteractionEnd(); + final ArgumentCaptor<AccessibilityEvent> captor = + ArgumentCaptor.forClass(AccessibilityEvent.class); + verify(mMockA11yEventSender, times(2)) + .sendAccessibilityEventForCurrentUserLocked(captor.capture()); + assertThat(captor.getAllValues().get(0), + allOf(displayId(Display.DEFAULT_DISPLAY), + a11yWindowId(eventWindowId), + a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE))); + assertThat(captor.getAllValues().get(1), + allOf(displayId(Display.DEFAULT_DISPLAY), + a11yWindowId(currentActiveWindowId), + a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE))); + } + + @Test + public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus() + throws RemoteException { + final IBinder defaultFocusWinToken = + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).token; + final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked( + USER_SYSTEM_ID, defaultFocusWinToken); + when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates()) + .thenReturn(defaultFocusWinToken); + final int newFocusWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, + DEFAULT_FOCUSED_INDEX + 1); + final IAccessibilityInteractionConnection mockNewFocusConnection = + mA11yWindowManager.getConnectionLocked( + USER_SYSTEM_ID, newFocusWindowId).getRemote(); + + mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY); + final int noUse = 0; + mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, + defaultFocusWindowId, + noUse, + AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, + noUse); + assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(defaultFocusWindowId)); + assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT), + is(defaultFocusWindowId)); + + mA11yWindowManager.onTouchInteractionStart(); + mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, + newFocusWindowId, + noUse, + AccessibilityEvent.TYPE_VIEW_HOVER_ENTER, + noUse); + mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID, + newFocusWindowId, + AccessibilityNodeInfo.ROOT_NODE_ID, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, + noUse); + assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(newFocusWindowId)); + assertThat(mA11yWindowManager.getFocusedWindowId( + AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(newFocusWindowId)); + + mA11yWindowManager.onTouchInteractionEnd(); + mHandler.sendLastMessage(); + verify(mockNewFocusConnection).clearAccessibilityFocus(); + } + + @Test + public void getPictureInPictureWindow_shouldNotNull() { + assertNull(mA11yWindowManager.getPictureInPictureWindowLocked()); + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1).inPictureInPicture = true; + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + + assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked()); + } + + @Test + public void notifyOutsideTouch() throws RemoteException { + final int targetWindowId = + getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 1); + final int outsideWindowId = + getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0); + final IAccessibilityInteractionConnection mockRemoteConnection = + mA11yWindowManager.getConnectionLocked( + USER_SYSTEM_ID, outsideWindowId).getRemote(); + mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0).hasFlagWatchOutsideTouch = true; + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES); + + mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId); + verify(mockRemoteConnection).notifyOutsideTouch(); + } + + @Test + public void addAccessibilityInteractionConnection_profileUser_findInParentUser() + throws RemoteException { + final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, + false, USER_PROFILE); + final int windowId = mA11yWindowManager.findWindowIdLocked( + USER_PROFILE_PARENT, token.asBinder()); + assertTrue(windowId >= 0); + } + + @Test + public void getDisplayList() throws RemoteException { + // Starts tracking window of second display. + startTrackingPerDisplay(SECONDARY_DISPLAY_ID); + + final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked( + DISPLAY_TYPE_DEFAULT); + assertTrue(displayList.equals(mExpectedDisplayList)); + } + + @Test + public void setAccessibilityWindowIdToSurfaceMetadata() + throws RemoteException { + final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, + true, USER_SYSTEM_ID); + int windowId = -1; + for (int i = 0; i < mA11yWindowTokens.size(); i++) { + if (mA11yWindowTokens.valueAt(i).equals(token)) { + windowId = mA11yWindowTokens.keyAt(i); + } + } + assertNotEquals("Returned token is not found in mA11yWindowTokens", -1, windowId); + verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata( + token.asBinder(), windowId); + + mA11yWindowManager.removeAccessibilityInteractionConnection(token); + verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata( + token.asBinder(), -1); + } + + @Test + public void getHostTokenLocked_hierarchiesAreAssociated_shouldReturnHostToken() { + mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken); + final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken); + assertEquals(hostToken, mMockHostToken); + } + + @Test + public void getHostTokenLocked_hierarchiesAreNotAssociated_shouldReturnNull() { + final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken); + assertNull(hostToken); + } + + @Test + public void getHostTokenLocked_embeddedHierarchiesAreDisassociated_shouldReturnNull() { + mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken); + mA11yWindowManager.disassociateLocked(mMockEmbeddedToken); + final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken); + assertNull(hostToken); + } + + @Test + public void getHostTokenLocked_hostHierarchiesAreDisassociated_shouldReturnNull() { + mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken); + mA11yWindowManager.disassociateLocked(mMockHostToken); + final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockHostToken); + assertNull(hostToken); + } + + @Test + public void getWindowIdLocked_windowIsRegistered_shouldReturnWindowId() { + final int windowId = mA11yWindowManager.getWindowIdLocked(mMockHostToken); + assertEquals(windowId, HOST_WINDOW_ID); + } + + @Test + public void getWindowIdLocked_windowIsNotRegistered_shouldReturnInvalidWindowId() { + final int windowId = mA11yWindowManager.getWindowIdLocked(mMockInvalidToken); + assertEquals(windowId, INVALID_ID); + } + + @Test + public void getTokenLocked_windowIsRegistered_shouldReturnToken() { + final IBinder token = mA11yWindowManager.getLeashTokenLocked(HOST_WINDOW_ID); + assertEquals(token, mMockHostToken); + } + + @Test + public void getTokenLocked_windowIsNotRegistered_shouldReturnNull() { + final IBinder token = mA11yWindowManager.getLeashTokenLocked(OTHER_WINDOW_ID); + assertNull(token); + } + + @Test + public void setAccessibilityWindowAttributes_windowIsNotRegistered_titleIsChanged() { + final int windowId = + getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0); + final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); + layoutParams.accessibilityTitle = "accessibility window title"; + final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes( + layoutParams, new LocaleList()); + + mA11yWindowManager.setAccessibilityWindowAttributes(Display.DEFAULT_DISPLAY, windowId, + USER_SYSTEM_ID, attributes); + + final AccessibilityWindowInfo a11yWindow = mA11yWindowManager.findA11yWindowInfoByIdLocked( + windowId); + assertEquals(toString(layoutParams.accessibilityTitle), toString(a11yWindow.getTitle())); + } + + @Test + public void sendAccessibilityEventOnWindowRemoval() { + final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY); + + // Removing index 0 because it's not focused, and avoids unnecessary layer change. + final int windowId = + getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0); + infos.remove(0); + for (WindowInfo info : infos) { + // Adjust layer number because it should start from 0. + info.layer--; + } + + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND); + + final ArgumentCaptor<AccessibilityEvent> captor = + ArgumentCaptor.forClass(AccessibilityEvent.class); + verify(mMockA11yEventSender, times(1)) + .sendAccessibilityEventForCurrentUserLocked(captor.capture()); + assertThat(captor.getAllValues().get(0), + allOf(displayId(Display.DEFAULT_DISPLAY), + a11yWindowId(windowId), + a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_REMOVED))); + } + + @Test + public void sendAccessibilityEventOnWindowAddition() throws RemoteException { + final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY); + + for (WindowInfo info : infos) { + // Adjust layer number because new window will have 0 so that layer number in + // A11yWindowInfo in window won't be changed. + info.layer++; + } + + final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, + false, USER_SYSTEM_ID); + addWindowInfo(infos, token, 0); + final int windowId = + getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, infos.size() - 1); + + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND); + + final ArgumentCaptor<AccessibilityEvent> captor = + ArgumentCaptor.forClass(AccessibilityEvent.class); + verify(mMockA11yEventSender, times(1)) + .sendAccessibilityEventForCurrentUserLocked(captor.capture()); + assertThat(captor.getAllValues().get(0), + allOf(displayId(Display.DEFAULT_DISPLAY), + a11yWindowId(windowId), + a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ADDED))); + } + + @Test + public void sendAccessibilityEventOnWindowChange() { + final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY); + infos.get(0).title = "new title"; + final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0); + + onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND); + + final ArgumentCaptor<AccessibilityEvent> captor = + ArgumentCaptor.forClass(AccessibilityEvent.class); + verify(mMockA11yEventSender, times(1)) + .sendAccessibilityEventForCurrentUserLocked(captor.capture()); + assertThat(captor.getAllValues().get(0), + allOf(displayId(Display.DEFAULT_DISPLAY), + a11yWindowId(windowId), + a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_TITLE))); + } + + private void registerLeashedTokenAndWindowId() { + mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID); + mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID); + } + + private void startTrackingPerDisplay(int displayId) throws RemoteException { + ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>(); + // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy + // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos + // for the test. + int layer = 0; + for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) { + final IWindow token = addAccessibilityInteractionConnection(displayId, + true, USER_SYSTEM_ID); + addWindowInfo(windowInfosForDisplay, token, layer++); + + } + for (int i = 0; i < NUM_APP_WINDOWS; i++) { + final IWindow token = addAccessibilityInteractionConnection(displayId, + false, USER_SYSTEM_ID); + addWindowInfo(windowInfosForDisplay, token, layer++); + } + // Sets up current focused window of display. + // Each display has its own current focused window if config_perDisplayFocusEnabled is true. + // Otherwise only default display needs to current focused window. + if (mSupportPerDisplayFocus || displayId == Display.DEFAULT_DISPLAY) { + windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true; + } + // Turns on windows tracking, and update window info. + mA11yWindowManager.startTrackingWindows(displayId, false); + // Puts window lists into array. + mWindowInfos.put(displayId, windowInfosForDisplay); + // Sets the default display is the top focused display and + // its current focused window is the top focused window. + if (displayId == Display.DEFAULT_DISPLAY) { + setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX); + } + // Invokes callback for sending window lists to A11y framework. + onWindowsForAccessibilityChanged(displayId, FORCE_SEND); + + assertEquals(mA11yWindowManager.getWindowListLocked(displayId).size(), + windowInfosForDisplay.size()); + } + + private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) { + ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor = + ArgumentCaptor.forClass( + WindowsForAccessibilityCallback.class); + verify(mMockWindowManagerInternal) + .setWindowsForAccessibilityCallback(eq(displayId), + windowsForAccessibilityCallbacksCaptor.capture()); + return windowsForAccessibilityCallbacksCaptor.getValue(); + } + + private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal, + int userId) throws RemoteException { + final IWindow mockWindowToken = Mockito.mock(IWindow.class); + final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock( + IAccessibilityInteractionConnection.class); + final IBinder mockConnectionBinder = Mockito.mock(IBinder.class); + final IBinder mockWindowBinder = Mockito.mock(IBinder.class); + final IBinder mockLeashToken = Mockito.mock(IBinder.class); + when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder); + when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder); + when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId)) + .thenReturn(bGlobal); + when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder)) + .thenReturn(displayId); + + int windowId = mA11yWindowManager.addAccessibilityInteractionConnection( + mockWindowToken, mockLeashToken, mockA11yConnection, PACKAGE_NAME, userId); + mA11yWindowTokens.put(windowId, mockWindowToken); + return mockWindowToken; + } + + private int addAccessibilityInteractionConnection(int displayId, boolean bGlobal, + IBinder leashToken, int userId) throws RemoteException { + final IWindow mockWindowToken = Mockito.mock(IWindow.class); + final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock( + IAccessibilityInteractionConnection.class); + final IBinder mockConnectionBinder = Mockito.mock(IBinder.class); + final IBinder mockWindowBinder = Mockito.mock(IBinder.class); + when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder); + when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder); + when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId)) + .thenReturn(bGlobal); + when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder)) + .thenReturn(displayId); + + int windowId = mA11yWindowManager.addAccessibilityInteractionConnection( + mockWindowToken, leashToken, mockA11yConnection, PACKAGE_NAME, userId); + mA11yWindowTokens.put(windowId, mockWindowToken); + return windowId; + } + + private void addWindowInfo(ArrayList<WindowInfo> windowInfos, IWindow windowToken, int layer) { + final WindowInfo windowInfo = WindowInfo.obtain(); + windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION; + windowInfo.token = windowToken.asBinder(); + windowInfo.layer = layer; + windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + windowInfos.add(windowInfo); + } + + private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) { + final IBinder windowToken = mWindowInfos.get(displayId).get(index).token; + return mA11yWindowManager.findWindowIdLocked( + USER_SYSTEM_ID, windowToken); + } + + private void setTopFocusedWindowAndDisplay(int displayId, int index) { + // Sets the top focus window. + mTopFocusedWindowToken = mWindowInfos.get(displayId).get(index).token; + // Sets the top focused display. + mTopFocusedDisplayId = displayId; + } + + private void onWindowsForAccessibilityChanged(int displayId, boolean forceSend) { + WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId); + if (callbacks == null) { + callbacks = getWindowsForAccessibilityCallbacks(displayId); + mCallbackOfWindows.put(displayId, callbacks); + } + callbacks.onWindowsForAccessibilityChanged(forceSend, mTopFocusedDisplayId, + mTopFocusedWindowToken, mWindowInfos.get(displayId)); + } + + private void changeFocusedWindowOnDisplayPerDisplayFocusConfig( + int changeFocusedDisplayId, int newFocusedWindowIndex, int oldTopFocusedDisplayId, + int oldFocusedWindowIndex) { + if (mSupportPerDisplayFocus) { + // Gets the old focused window of display which wants to change focused window. + WindowInfo focusedWindowInfo = + mWindowInfos.get(changeFocusedDisplayId).get(oldFocusedWindowIndex); + // Resets the focus of old focused window. + focusedWindowInfo.focused = false; + // Gets the new window of display which wants to change focused window. + focusedWindowInfo = + mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex); + // Sets the focus of new focused window. + focusedWindowInfo.focused = true; + } else { + // Gets the window of display which wants to change focused window. + WindowInfo focusedWindowInfo = + mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex); + // Sets the focus of new focused window. + focusedWindowInfo.focused = true; + // Gets the old focused window of old top focused display. + focusedWindowInfo = + mWindowInfos.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex); + // Resets the focus of old focused window. + focusedWindowInfo.focused = false; + // Changes the top focused display and window. + setTopFocusedWindowAndDisplay(changeFocusedDisplayId, newFocusedWindowIndex); + } + } + + @Nullable + private static String toString(@Nullable CharSequence cs) { + return cs == null ? null : cs.toString(); + } + + static class DisplayIdMatcher extends TypeSafeMatcher<AccessibilityEvent> { + private final int mDisplayId; + + DisplayIdMatcher(int displayId) { + super(); + mDisplayId = displayId; + } + + static DisplayIdMatcher displayId(int displayId) { + return new DisplayIdMatcher(displayId); + } + + @Override + protected boolean matchesSafely(AccessibilityEvent event) { + return event.getDisplayId() == mDisplayId; + } + + @Override + public void describeTo(Description description) { + description.appendText("Matching to displayId " + mDisplayId); + } + } + + static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> { + private int mWindowId; + + WindowIdMatcher(int windowId) { + super(); + mWindowId = windowId; + } + + static WindowIdMatcher a11yWindowId(int windowId) { + return new WindowIdMatcher(windowId); + } + + @Override + protected boolean matchesSafely(AccessibilityEvent event) { + return event.getWindowId() == mWindowId; + } + + @Override + public void describeTo(Description description) { + description.appendText("Matching to windowId " + mWindowId); + } + } + + static class WindowChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> { + private int mWindowChanges; + + WindowChangesMatcher(int windowChanges) { + super(); + mWindowChanges = windowChanges; + } + + static WindowChangesMatcher a11yWindowChanges(int windowChanges) { + return new WindowChangesMatcher(windowChanges); + } + + @Override + protected boolean matchesSafely(AccessibilityEvent event) { + return event.getWindowChanges() == mWindowChanges; + } + + @Override + public void describeTo(Description description) { + description.appendText("Matching to window changes " + mWindowChanges); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java index 009bfb7efca6..87fe6cf8f283 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java @@ -813,6 +813,18 @@ public class MagnificationConnectionManagerTest { anyBoolean()); } + @Test + public void onFullscreenMagnificationActivationChanged_hasConnection_notifyActivatedState() + throws RemoteException { + mMagnificationConnectionManager.setConnection(mMockConnection.getConnection()); + + mMagnificationConnectionManager + .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true); + + verify(mMockConnection.getConnection()) + .onFullscreenMagnificationActivationChanged(eq(TEST_DISPLAY), eq(true)); + } + private MotionEvent generatePointersDownEvent(PointF[] pointersLocation) { final int len = pointersLocation.length; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionWrapperTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionWrapperTest.java index 07f3036410a0..2120b2e8e1f3 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionWrapperTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionWrapperTest.java @@ -131,6 +131,14 @@ public class MagnificationConnectionWrapperTest { } @Test + public void onFullscreenMagnificationActivationChanged() throws RemoteException { + mConnectionWrapper + .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true); + verify(mConnection) + .onFullscreenMagnificationActivationChanged(eq(TEST_DISPLAY), eq(true)); + } + + @Test public void setMirrorWindowCallback() throws RemoteException { mConnectionWrapper.setConnectionCallback(mCallback); verify(mConnection).setConnectionCallback(mCallback); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java index a0c4b5e26c3f..1a51c45e2ef6 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java @@ -53,6 +53,10 @@ import android.hardware.display.DisplayManagerInternal; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import android.test.mock.MockContentResolver; import android.testing.DexmakerShareClassLoaderRule; @@ -73,6 +77,7 @@ import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.accessibility.AccessibilityTraceManager; import com.android.server.accessibility.test.MessageCapturingHandler; import com.android.server.wm.WindowManagerInternal; +import com.android.window.flags.Flags; import org.junit.After; import org.junit.Before; @@ -91,6 +96,9 @@ import org.mockito.stubbing.Answer; @RunWith(AndroidJUnit4.class) public class MagnificationControllerTest { + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY; private static final int TEST_SERVICE_ID = 1; private static final Region INITIAL_SCREEN_MAGNIFICATION_REGION = @@ -1263,6 +1271,27 @@ public class MagnificationControllerTest { verify(mService).changeMagnificationMode(TEST_DISPLAY, MODE_WINDOW); } + @Test + @RequiresFlagsEnabled(Flags.FLAG_MAGNIFICATION_ALWAYS_DRAW_FULLSCREEN_BORDER) + public void onFullscreenMagnificationActivationState_systemUiBorderFlagOn_notifyConnection() { + mMagnificationController.onFullScreenMagnificationActivationState( + TEST_DISPLAY, /* activated= */ true); + + verify(mMagnificationConnectionManager) + .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true); + } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_MAGNIFICATION_ALWAYS_DRAW_FULLSCREEN_BORDER) + public void + onFullscreenMagnificationActivationState_systemUiBorderFlagOff_neverNotifyConnection() { + mMagnificationController.onFullScreenMagnificationActivationState( + TEST_DISPLAY, /* activated= */ true); + + verify(mMagnificationConnectionManager, never()) + .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true); + } + private void setMagnificationEnabled(int mode) throws RemoteException { setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y); } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java index a6e05ddc792c..55208972895d 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java @@ -364,6 +364,30 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test + public void systemAudioControlOnPowerOn_singleActionStarted() throws Exception { + mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class); + mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn( + Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true); + mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn( + Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true); + assertThat( + mHdmiCecLocalDeviceAudioSystem.getActions( + SystemAudioInitiationActionFromAvr.class)) + .hasSize(1); + } + + @Test + public void onSystemAudioControlFeatureSupportChanged_singleActionStarted() throws Exception { + mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class); + mHdmiCecLocalDeviceAudioSystem.onSystemAudioControlFeatureSupportChanged(true); + mHdmiCecLocalDeviceAudioSystem.onSystemAudioControlFeatureSupportChanged(true); + assertThat( + mHdmiCecLocalDeviceAudioSystem.getActions( + SystemAudioInitiationActionFromAvr.class)) + .hasSize(1); + } + + @Test public void handleActiveSource_updateActiveSource() throws Exception { HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000); ActiveSource expectedActiveSource = new ActiveSource(ADDR_TV, 0x0000); diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 5c6f3c92204a..15cd5115a49e 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -149,6 +149,7 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkPolicy; +import android.net.NetworkPolicyManager; import android.net.NetworkStateSnapshot; import android.net.NetworkTemplate; import android.net.TelephonyNetworkSpecifier; @@ -1619,6 +1620,12 @@ public class NetworkPolicyManagerServiceTest { verify(mActivityManagerInternal).notifyNetworkPolicyRulesUpdated(UID_A, procStateSeq); } + private void callAndWaitOnUidGone(int uid) throws Exception { + // The disabled argument is used only for ephemeral apps and does not matter here. + mUidObserver.onUidGone(uid, false /* disabled */); + waitForUidEventHandlerIdle(); + } + private void callAndWaitOnUidStateChanged(int uid, int procState, long procStateSeq) throws Exception { callAndWaitOnUidStateChanged(uid, procState, procStateSeq, @@ -2245,6 +2252,15 @@ public class NetworkPolicyManagerServiceTest { assertTrue(mService.isUidNetworkingBlocked(UID_A, false)); } + private boolean isUidState(int uid, int procState, int procStateSeq, int capability) { + final NetworkPolicyManager.UidState uidState = mService.getUidStateForTest(uid); + if (uidState == null) { + return false; + } + return uidState.uid == uid && uidState.procStateSeq == procStateSeq + && uidState.procState == procState && uidState.capability == capability; + } + @Test @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE) public void testUidObserverFiltersProcStateChanges() throws Exception { @@ -2363,6 +2379,31 @@ public class NetworkPolicyManagerServiceTest { } @Test + public void testUidStateChangeAfterUidGone() throws Exception { + final int testProcStateSeq = 51; + final int testProcState = PROCESS_STATE_IMPORTANT_FOREGROUND; + + try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) { + // First callback for uid. + callOnUidStatechanged(UID_B, testProcState, testProcStateSeq, PROCESS_CAPABILITY_NONE); + assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED)); + } + waitForUidEventHandlerIdle(); + assertTrue(isUidState(UID_B, testProcState, testProcStateSeq, PROCESS_CAPABILITY_NONE)); + + callAndWaitOnUidGone(UID_B); + try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) { + // Even though the procState is the same, the uid had exited - so this should be + // processed as a fresh callback. + callOnUidStatechanged(UID_B, testProcState, testProcStateSeq + 1, + PROCESS_CAPABILITY_NONE); + assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED)); + } + waitForUidEventHandlerIdle(); + assertTrue(isUidState(UID_B, testProcState, testProcStateSeq + 1, PROCESS_CAPABILITY_NONE)); + } + + @Test public void testLowPowerStandbyAllowlist() throws Exception { // Chain background is also enabled but these procstates are important enough to be exempt. callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, 0); diff --git a/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java b/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java index c8bef45af839..076d5caf5954 100644 --- a/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java +++ b/services/tests/servicestests/src/com/android/server/utils/AnrTimerTest.java @@ -312,10 +312,12 @@ public class AnrTimerTest { } /** - * Verify the dump output. + * Verify the dump output. This only applies when native timers are supported. */ @Test public void testDumpOutput() throws Exception { + if (!AnrTimer.nativeTimersSupported()) return; + String r1 = getDumpOutput(); assertThat(r1).doesNotContain("timer:"); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 8c50ef406ec6..8c2fd1013056 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -4420,13 +4420,13 @@ public class ZenModeHelperTest extends UiServiceTestCase { @EnableFlags(Flags.FLAG_MODES_API) public void updateAutomaticZenRule_nullDeviceEffectsUpdate() { // Adds a starting rule with empty zen policies and device effects + ZenDeviceEffects zde = new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build(); AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID) - .setDeviceEffects(new ZenDeviceEffects.Builder().build()) + .setDeviceEffects(zde) .build(); // Adds the rule using the app, to avoid having any user modified bits set. String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), azrBase, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID); - AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId); AutomaticZenRule azr = new AutomaticZenRule.Builder(azrBase) // Sets Device Effects to null @@ -4437,10 +4437,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { // user modified, it can be updated. mZenModeHelper.updateAutomaticZenRule(ruleId, azr, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID); - rule = mZenModeHelper.getAutomaticZenRule(ruleId); + AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId); - // When AZR's ZenDeviceEffects is null, the updated rule's device effects will be null. - assertThat(rule.getDeviceEffects()).isNull(); + // When AZR's ZenDeviceEffects is null, the updated rule's device effects are kept. + assertThat(rule.getDeviceEffects()).isEqualTo(zde); } @Test diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java index 417fbd06be66..0d5bf95d959d 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java @@ -67,6 +67,7 @@ public class VibratorControlServiceTest { @Mock private PackageManagerInternal mPackageManagerInternalMock; + private TestLooper mTestLooper; private FakeVibratorController mFakeVibratorController; private VibratorControlService mVibratorControlService; private VibrationSettings mVibrationSettings; @@ -74,6 +75,7 @@ public class VibratorControlServiceTest { @Before public void setUp() throws Exception { + mTestLooper = new TestLooper(); when(mPackageManagerInternalMock.getSystemUiServiceComponent()) .thenReturn(new ComponentName("", "")); LocalServices.removeServiceForTest(PackageManagerInternal.class); @@ -83,7 +85,7 @@ public class VibratorControlServiceTest { mVibrationSettings = new VibrationSettings( ApplicationProvider.getApplicationContext(), new Handler(testLooper.getLooper())); - mFakeVibratorController = new FakeVibratorController(); + mFakeVibratorController = new FakeVibratorController(mTestLooper.getLooper()); mVibratorControlService = new VibratorControlService(new VibratorControllerHolder(), mMockVibrationScaler, mVibrationSettings, mLock); } @@ -108,13 +110,13 @@ public class VibratorControlServiceTest { @Test public void testUnregisterVibratorController_providingAnInvalidController_ignoresRequest() throws RemoteException { - FakeVibratorController fakeController1 = new FakeVibratorController(); - FakeVibratorController fakeController2 = new FakeVibratorController(); - mVibratorControlService.registerVibratorController(fakeController1); - mVibratorControlService.unregisterVibratorController(fakeController2); + FakeVibratorController controller1 = new FakeVibratorController(mTestLooper.getLooper()); + FakeVibratorController controller2 = new FakeVibratorController(mTestLooper.getLooper()); + mVibratorControlService.registerVibratorController(controller1); + mVibratorControlService.unregisterVibratorController(controller2); verifyZeroInteractions(mMockVibrationScaler); - assertThat(fakeController1.isLinkedToDeath).isTrue(); + assertThat(controller1.isLinkedToDeath).isTrue(); } @Test diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java index 79abe21a301d..db823d649cb6 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java @@ -18,23 +18,26 @@ package com.android.server.vibrator; import static com.google.common.truth.Truth.assertThat; -import android.os.RemoteException; +import android.os.test.TestLooper; import org.junit.Before; import org.junit.Test; public class VibratorControllerHolderTest { - private final FakeVibratorController mFakeVibratorController = new FakeVibratorController(); + private TestLooper mTestLooper; + private FakeVibratorController mFakeVibratorController; private VibratorControllerHolder mVibratorControllerHolder; @Before public void setUp() throws Exception { + mTestLooper = new TestLooper(); + mFakeVibratorController = new FakeVibratorController(mTestLooper.getLooper()); mVibratorControllerHolder = new VibratorControllerHolder(); } @Test - public void testSetVibratorController_linksVibratorControllerToDeath() throws RemoteException { + public void testSetVibratorController_linksVibratorControllerToDeath() { mVibratorControllerHolder.setVibratorController(mFakeVibratorController); assertThat(mVibratorControllerHolder.getVibratorController()) .isEqualTo(mFakeVibratorController); @@ -42,8 +45,7 @@ public class VibratorControllerHolderTest { } @Test - public void testSetVibratorController_setControllerToNull_unlinksVibratorControllerToDeath() - throws RemoteException { + public void testSetVibratorController_setControllerToNull_unlinksVibratorControllerToDeath() { mVibratorControllerHolder.setVibratorController(mFakeVibratorController); mVibratorControllerHolder.setVibratorController(null); assertThat(mFakeVibratorController.isLinkedToDeath).isFalse(); @@ -51,8 +53,7 @@ public class VibratorControllerHolderTest { } @Test - public void testBinderDied_withValidController_unlinksVibratorControllerToDeath() - throws RemoteException { + public void testBinderDied_withValidController_unlinksVibratorControllerToDeath() { mVibratorControllerHolder.setVibratorController(mFakeVibratorController); mVibratorControllerHolder.binderDied(mFakeVibratorController); assertThat(mFakeVibratorController.isLinkedToDeath).isFalse(); @@ -60,10 +61,10 @@ public class VibratorControllerHolderTest { } @Test - public void testBinderDied_withInvalidController_ignoresRequest() - throws RemoteException { + public void testBinderDied_withInvalidController_ignoresRequest() { mVibratorControllerHolder.setVibratorController(mFakeVibratorController); - FakeVibratorController imposterVibratorController = new FakeVibratorController(); + FakeVibratorController imposterVibratorController = + new FakeVibratorController(mTestLooper.getLooper()); mVibratorControllerHolder.binderDied(imposterVibratorController); assertThat(mFakeVibratorController.isLinkedToDeath).isTrue(); assertThat(mVibratorControllerHolder.getVibratorController()) diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java index ed89ccf07453..d2ad61f2ba9f 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -97,7 +97,6 @@ import android.view.InputDevice; import android.view.flags.Flags; import androidx.test.InstrumentationRegistry; -import androidx.test.filters.FlakyTest; import com.android.internal.app.IBatteryStats; import com.android.internal.util.FrameworkStatsLog; @@ -117,6 +116,7 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.time.Duration; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -128,9 +128,7 @@ import java.util.function.Predicate; public class VibratorManagerServiceTest { private static final int TEST_TIMEOUT_MILLIS = 1_000; - // Time to allow for a cancellation to complete (notably including system ramp down), but not so - // long that tests easily get really slow or flaky. If a vibration is close to this, it should - // be cancelled in the body of the individual test. + // Time to allow for a cancellation to complete and the vibrators to become idle. private static final int CLEANUP_TIMEOUT_MILLIS = 100; private static final int UID = Process.ROOT_UID; private static final int VIRTUAL_DEVICE_ID = 1; @@ -186,8 +184,8 @@ public class VibratorManagerServiceTest { private AudioManager mAudioManagerMock; private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>(); - - private SparseArray<VibrationEffect> mHapticFeedbackVibrationMap = new SparseArray<>(); + private final SparseArray<VibrationEffect> mHapticFeedbackVibrationMap = new SparseArray<>(); + private final List<HalVibration> mPendingVibrations = new ArrayList<>(); private VibratorManagerService mService; private Context mContextSpy; @@ -207,7 +205,7 @@ public class VibratorManagerServiceTest { mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); mInputManagerGlobalSession = InputManagerGlobal.createTestSession(mIInputManagerMock); mVibrationConfig = new VibrationConfig(mContextSpy.getResources()); - mFakeVibratorController = new FakeVibratorController(); + mFakeVibratorController = new FakeVibratorController(mTestLooper.getLooper()); ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy); when(mContextSpy.getContentResolver()).thenReturn(contentResolver); @@ -253,12 +251,15 @@ public class VibratorManagerServiceTest { @After public void tearDown() throws Exception { if (mService != null) { - // Wait until all vibrators have stopped vibrating, with a bit of flexibility for tests - // that just do a click or have cancelled at the end (waiting for ramp-down). - // - // Note: if a test is flaky here, check whether a VibrationEffect duration is close to - // CLEANUP_TIMEOUT_MILLIS - in which case it's probably best to just cancel that effect - // explicitly at the end of the test case (rather than letting it run and race flakily). + if (!mPendingVibrations.stream().allMatch(HalVibration::hasEnded)) { + // Cancel any pending vibration from tests. + cancelVibrate(mService); + for (HalVibration vibration : mPendingVibrations) { + vibration.waitForEnd(); + } + } + // Wait until all vibrators have stopped vibrating, waiting for ramp-down. + // Note: if a test is flaky here something is wrong with the vibration finalization. assertTrue(waitUntil(s -> { for (int vibratorId : mService.getVibratorIds()) { if (s.isVibrating(vibratorId)) { @@ -266,7 +267,7 @@ public class VibratorManagerServiceTest { } } return true; - }, mService, CLEANUP_TIMEOUT_MILLIS)); + }, mService, mVibrationConfig.getRampDownDurationMs() + CLEANUP_TIMEOUT_MILLIS)); } LocalServices.removeServiceForTest(PackageManagerInternal.class); @@ -323,21 +324,26 @@ public class VibratorManagerServiceTest { (VibratorManagerService.ExternalVibratorService) service; } else if (service instanceof VibratorControlService) { mVibratorControlService = (VibratorControlService) service; + mFakeVibratorController.setVibratorControlService( + mVibratorControlService); } } + @Override HapticFeedbackVibrationProvider createHapticFeedbackVibrationProvider( Resources resources, VibratorInfo vibratorInfo) { return new HapticFeedbackVibrationProvider( resources, vibratorInfo, mHapticFeedbackVibrationMap); } + @Override VibratorControllerHolder createVibratorControllerHolder() { VibratorControllerHolder holder = new VibratorControllerHolder(); holder.setVibratorController(mFakeVibratorController); return holder; } + @Override boolean isServiceDeclared(String name) { return true; } @@ -486,8 +492,9 @@ public class VibratorManagerServiceTest { InOrder inOrderVerifier = inOrder(listenerMock); // First notification done when listener is registered. inOrderVerifier.verify(listenerMock).onVibrating(eq(false)); + // Vibrator on notification done before vibration ended, no need to wait. inOrderVerifier.verify(listenerMock).onVibrating(eq(true)); - // The last notification is after the vibration has completed. + // Vibrator off notification done after vibration completed, wait for notification. inOrderVerifier.verify(listenerMock, timeout(TEST_TIMEOUT_MILLIS)).onVibrating(eq(false)); inOrderVerifier.verifyNoMoreInteractions(); @@ -517,6 +524,7 @@ public class VibratorManagerServiceTest { InOrder inOrderVerifier = inOrder(listenerMock); // First notification done when listener is registered. inOrderVerifier.verify(listenerMock).onVibrating(eq(false)); + // Vibrator on notification done before vibration ended, no need to wait. inOrderVerifier.verify(listenerMock).onVibrating(eq(true)); inOrderVerifier.verify(listenerMock, atLeastOnce()).asBinder(); // unregister inOrderVerifier.verifyNoMoreInteractions(); @@ -541,7 +549,6 @@ public class VibratorManagerServiceTest { verify(listeners[0]).onVibrating(eq(true)); verify(listeners[1]).onVibrating(eq(true)); verify(listeners[2], never()).onVibrating(eq(true)); - cancelVibrate(service); // Clean up long-ish effect. } @Test @@ -889,21 +896,24 @@ public class VibratorManagerServiceTest { eq(AudioAttributes.USAGE_UNKNOWN), anyInt(), anyString()); } - @FlakyTest @Test public void vibrate_withOngoingRepeatingVibration_ignoresEffect() throws Exception { mockVibrators(1); - mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); + fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); VibratorManagerService service = createSystemReadyService(); VibrationEffect repeatingEffect = VibrationEffect.createWaveform( - new long[]{10_000, 10_000}, new int[]{128, 255}, 1); - vibrate(service, repeatingEffect, new VibrationAttributes.Builder().setUsage( - VibrationAttributes.USAGE_UNKNOWN).build()); + new long[]{10, 10_000}, new int[]{128, 255}, 1); + vibrate(service, repeatingEffect, + new VibrationAttributes.Builder() + .setUsage(VibrationAttributes.USAGE_UNKNOWN) + .build()); - // VibrationThread will start this vibration async, wait until it has started. - assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), - service, TEST_TIMEOUT_MILLIS)); + // VibrationThread will start this vibration async. + // Wait until second step started to ensure the noteVibratorOn was triggered. + assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service, + TEST_TIMEOUT_MILLIS)); vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), HAPTIC_FEEDBACK_ATTRS); @@ -914,9 +924,8 @@ public class VibratorManagerServiceTest { // The second vibration shouldn't have recorded that the vibrators were turned on. verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong()); // No segment played is the prebaked CLICK from the second vibration. - assertFalse(mVibratorProviders.get(1).getAllEffectSegments().stream() + assertFalse(fakeVibrator.getAllEffectSegments().stream() .anyMatch(PrebakedSegment.class::isInstance)); - cancelVibrate(service); // Clean up repeating effect. } @Test @@ -930,11 +939,13 @@ public class VibratorManagerServiceTest { VibratorManagerService service = createSystemReadyService(); VibrationEffect repeatingEffect = VibrationEffect.createWaveform( - new long[]{10, 10_000}, new int[]{255, 0}, 1); + new long[]{10, 10_000}, new int[]{128, 255}, 1); vibrate(service, repeatingEffect, ALARM_ATTRS); - // VibrationThread will start this vibration async, wait until the off waveform step. - assertTrue(waitUntil(s -> fakeVibrator.getOffCount() > 0, service, TEST_TIMEOUT_MILLIS)); + // VibrationThread will start this vibration async. + // Wait until second step started to ensure the noteVibratorOn was triggered. + assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service, + TEST_TIMEOUT_MILLIS)); // Cancel vibration right before requesting a new one. // This should trigger slow IVibrator.off before setting the vibration status to cancelled. @@ -942,6 +953,8 @@ public class VibratorManagerServiceTest { vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS); + // The second vibration should have recorded that the vibrators were turned on. + verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong()); // Check that second vibration was played. assertTrue(fakeVibrator.getAllEffectSegments().stream() .anyMatch(PrebakedSegment.class::isInstance)); @@ -951,45 +964,47 @@ public class VibratorManagerServiceTest { public void vibrate_withNewSameImportanceVibrationAndBothRepeating_cancelsOngoingEffect() throws Exception { mockVibrators(1); - mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); + fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); VibratorManagerService service = createSystemReadyService(); VibrationEffect repeatingEffect = VibrationEffect.createWaveform( - new long[]{10_000, 10_000}, new int[]{128, 255}, 1); + new long[]{10, 10_000}, new int[]{128, 255}, 1); vibrate(service, repeatingEffect, ALARM_ATTRS); - // VibrationThread will start this vibration async, wait until it has started. - assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), - service, TEST_TIMEOUT_MILLIS)); + // VibrationThread will start this vibration async. + // Wait until second step started to ensure the noteVibratorOn was triggered. + assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service, + TEST_TIMEOUT_MILLIS)); VibrationEffect repeatingEffect2 = VibrationEffect.createWaveform( - new long[]{10_000, 10_000}, new int[]{128, 255}, 1); + new long[]{10, 10_000}, new int[]{255, 128}, 1); vibrate(service, repeatingEffect2, ALARM_ATTRS); - // VibrationThread will start this vibration async, so wait before checking it started. - assertTrue(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() == 2, - service, TEST_TIMEOUT_MILLIS)); + // VibrationThread will start this vibration async. + // Wait until second step started to ensure the noteVibratorOn was triggered. + assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 4, service, + TEST_TIMEOUT_MILLIS)); // The second vibration should have recorded that the vibrators were turned on. verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong()); - - cancelVibrate(service); // Clean up repeating effect. } - @FlakyTest @Test public void vibrate_withNewSameImportanceVibrationButOngoingIsRepeating_ignoreNewVibration() throws Exception { mockVibrators(1); FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); + fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); VibratorManagerService service = createSystemReadyService(); VibrationEffect repeatingEffect = VibrationEffect.createWaveform( - new long[]{10, 10_000}, new int[]{255, 0}, 1); + new long[]{10, 10_000}, new int[]{128, 255}, 1); vibrate(service, repeatingEffect, ALARM_ATTRS); - // VibrationThread will start this vibration async, wait until it has started. - assertTrue(waitUntil(s -> !fakeVibrator.getAllEffectSegments().isEmpty(), service, + // VibrationThread will start this vibration async. + // Wait until second step started to ensure the noteVibratorOn was triggered. + assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service, TEST_TIMEOUT_MILLIS)); vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), @@ -998,53 +1013,55 @@ public class VibratorManagerServiceTest { // The second vibration shouldn't have recorded that the vibrators were turned on. verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong()); // The second vibration shouldn't have played any prebaked segment. - assertFalse(mVibratorProviders.get(1).getAllEffectSegments().stream() + assertFalse(fakeVibrator.getAllEffectSegments().stream() .anyMatch(PrebakedSegment.class::isInstance)); - cancelVibrate(service); // Clean up long effect. } @Test public void vibrate_withNewUnknownUsageVibrationAndRepeating_cancelsOngoingEffect() throws Exception { mockVibrators(1); + FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); + fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); VibratorManagerService service = createSystemReadyService(); VibrationEffect repeatingEffect = VibrationEffect.createWaveform( - new long[]{10_000, 10_000}, new int[]{128, 255}, 1); + new long[]{10, 10_000}, new int[]{128, 255}, 1); vibrate(service, repeatingEffect, ALARM_ATTRS); - // VibrationThread will start this vibration async, wait until it has started. - assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), - service, TEST_TIMEOUT_MILLIS)); + // VibrationThread will start this vibration async. + // Wait until second step started to ensure the noteVibratorOn was triggered. + assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service, + TEST_TIMEOUT_MILLIS)); VibrationEffect repeatingEffect2 = VibrationEffect.createWaveform( - new long[]{10_000, 10_000}, new int[]{128, 255}, 1); + new long[]{10, 10_000}, new int[]{255, 128}, 1); vibrate(service, repeatingEffect2, UNKNOWN_ATTRS); - // VibrationThread will start this vibration async, so wait before checking it started. - assertTrue(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() == 2, - service, TEST_TIMEOUT_MILLIS)); + // VibrationThread will start this vibration async. + // Wait until second step started to ensure the noteVibratorOn was triggered. + assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 4, service, + TEST_TIMEOUT_MILLIS)); // The second vibration should have recorded that the vibrators were turned on. verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong()); - - cancelVibrate(service); // Clean up repeating effect. } - @FlakyTest @Test public void vibrate_withNewUnknownUsageVibrationAndNotRepeating_ignoreNewVibration() throws Exception { mockVibrators(1); FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); + fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); VibratorManagerService service = createSystemReadyService(); VibrationEffect alarmEffect = VibrationEffect.createWaveform( - new long[]{10, 10_000}, new int[]{255, 0}, -1); + new long[]{10, 10_000}, new int[]{128, 255}, -1); vibrate(service, alarmEffect, ALARM_ATTRS); - // VibrationThread will start this vibration async, wait until it has started. - assertTrue(waitUntil(s -> !fakeVibrator.getAllEffectSegments().isEmpty(), service, + // VibrationThread will start this vibration async. + // Wait until second step started to ensure the noteVibratorOn was triggered. + assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service, TEST_TIMEOUT_MILLIS)); vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), @@ -1053,23 +1070,24 @@ public class VibratorManagerServiceTest { // The second vibration shouldn't have recorded that the vibrators were turned on. verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong()); // The second vibration shouldn't have played any prebaked segment. - assertFalse(mVibratorProviders.get(1).getAllEffectSegments().stream() + assertFalse(fakeVibrator.getAllEffectSegments().stream() .anyMatch(PrebakedSegment.class::isInstance)); - cancelVibrate(service); // Clean up long effect. } @Test public void vibrate_withOngoingHigherImportanceVibration_ignoresEffect() throws Exception { mockVibrators(1); - mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); + fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); VibratorManagerService service = createSystemReadyService(); VibrationEffect effect = VibrationEffect.createWaveform( - new long[]{10_000, 10_000}, new int[]{128, 255}, -1); + new long[]{10, 10_000}, new int[]{128, 255}, -1); vibrate(service, effect, ALARM_ATTRS); - // VibrationThread will start this vibration async, so wait before checking it started. - assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), + // VibrationThread will start this vibration async. + // Wait until second step started to ensure the noteVibratorOn was triggered. + assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service, TEST_TIMEOUT_MILLIS)); vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), @@ -1078,26 +1096,27 @@ public class VibratorManagerServiceTest { // The second vibration shouldn't have recorded that the vibrators were turned on. verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong()); // The second vibration shouldn't have played any prebaked segment. - assertFalse(mVibratorProviders.get(1).getAllEffectSegments().stream() + assertFalse(fakeVibrator.getAllEffectSegments().stream() .anyMatch(PrebakedSegment.class::isInstance)); - cancelVibrate(service); // Clean up long effect. } @Test public void vibrate_withOngoingLowerImportanceVibration_cancelsOngoingEffect() throws Exception { mockVibrators(1); - mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); - mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK); + FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); + fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK); VibratorManagerService service = createSystemReadyService(); VibrationEffect effect = VibrationEffect.createWaveform( - new long[]{10_000, 10_000}, new int[]{128, 255}, -1); + new long[]{10, 10_000}, new int[]{128, 255}, -1); vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS); - // VibrationThread will start this vibration async, so wait before checking it started. - assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(), - service, TEST_TIMEOUT_MILLIS)); + // VibrationThread will start this vibration async. + // Wait until second step started to ensure the noteVibratorOn was triggered. + assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service, + TEST_TIMEOUT_MILLIS)); vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), RINGTONE_ATTRS); @@ -1105,10 +1124,8 @@ public class VibratorManagerServiceTest { // The second vibration should have recorded that the vibrators were turned on. verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong()); // One segment played is the prebaked CLICK from the second vibration. - assertEquals(1, - mVibratorProviders.get(1).getAllEffectSegments().stream() - .filter(PrebakedSegment.class::isInstance) - .count()); + assertEquals(1, fakeVibrator.getAllEffectSegments().stream() + .filter(PrebakedSegment.class::isInstance).count()); } @Test @@ -1139,10 +1156,8 @@ public class VibratorManagerServiceTest { // The new vibration should have recorded that the vibrators were turned on. verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong()); // One segment played is the prebaked CLICK from the new vibration. - assertEquals(1, - mVibratorProviders.get(1).getAllEffectSegments().stream() - .filter(PrebakedSegment.class::isInstance) - .count()); + assertEquals(1, mVibratorProviders.get(1).getAllEffectSegments().stream() + .filter(PrebakedSegment.class::isInstance).count()); } @Test @@ -1153,8 +1168,9 @@ public class VibratorManagerServiceTest { .build(); mockVibrators(1); - mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); - mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK); + FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); + fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK); VibratorManagerService service = createSystemReadyService(); VibrationEffect effect = VibrationEffect.createWaveform( @@ -1173,7 +1189,7 @@ public class VibratorManagerServiceTest { verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong()); // One step segment (with several amplitudes) and one click should have played. Notably // there is no primitive segment. - List<VibrationEffectSegment> played = mVibratorProviders.get(1).getAllEffectSegments(); + List<VibrationEffectSegment> played = fakeVibrator.getAllEffectSegments(); assertEquals(2, played.size()); assertEquals(1, played.stream().filter(StepSegment.class::isInstance).count()); assertEquals(1, played.stream().filter(PrebakedSegment.class::isInstance).count()); @@ -1182,8 +1198,9 @@ public class VibratorManagerServiceTest { @Test public void vibrate_withInputDevices_vibratesInputDevices() throws Exception { mockVibrators(1); - mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); - mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK); + FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1); + fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS); + fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK); when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1}); when(mIInputManagerMock.getVibratorIds(eq(1))).thenReturn(new int[]{1}); when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(createInputDeviceWithVibrator(1)); @@ -1198,7 +1215,7 @@ public class VibratorManagerServiceTest { vibrateAndWaitUntilFinished(service, effect, ALARM_ATTRS); verify(mIInputManagerMock).vibrateCombined(eq(1), eq(effect), any()); - assertTrue(mVibratorProviders.get(1).getAllEffectSegments().isEmpty()); + assertTrue(fakeVibrator.getAllEffectSegments().isEmpty()); } @Test @@ -1497,8 +1514,6 @@ public class VibratorManagerServiceTest { // Alarm vibration will be scaled with SCALE_NONE. assertEquals(1f, ((PrimitiveSegment) fakeVibrator.getAllEffectSegments().get(2)).getScale(), 1e-5); - - cancelVibrate(service); // Clean up long-ish effect. } @Test @@ -1533,8 +1548,6 @@ public class VibratorManagerServiceTest { assertEquals(1, fakeVibrator.getAllEffectSegments().size()); assertEquals(defaultAmplitude / 255f, fakeVibrator.getAmplitudes().get(0), 1e-5); - - cancelVibrate(service); // Clean up long-ish effect. } @Test @@ -1570,7 +1583,6 @@ public class VibratorManagerServiceTest { // Vibration is not stopped nearly after updating service. assertFalse(waitUntil(s -> !s.isVibrating(1), service, 50)); - cancelVibrate(service); // Clean up long effect. } @Test @@ -1596,8 +1608,6 @@ public class VibratorManagerServiceTest { HAPTIC_FEEDBACK_ATTRS); // Haptic feedback played normally when it's from the default device. assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS)); - - cancelVibrate(service); // Clean up long-ish effect. } @Test @@ -1854,9 +1864,7 @@ public class VibratorManagerServiceTest { assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); // Vibration is not cancelled. - assertFalse(waitUntil(s -> !s.isVibrating(1), service, CLEANUP_TIMEOUT_MILLIS)); assertEquals(Arrays.asList(false), mVibratorProviders.get(1).getExternalControlStates()); - cancelVibrate(service); // Clean up long effect. } @Test @@ -1910,9 +1918,7 @@ public class VibratorManagerServiceTest { assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel); // Vibration is not cancelled. - assertFalse(waitUntil(s -> !s.isVibrating(1), service, CLEANUP_TIMEOUT_MILLIS)); assertEquals(Arrays.asList(false), mVibratorProviders.get(1).getExternalControlStates()); - cancelVibrate(service); // Clean up long effect. } @Test @@ -2536,29 +2542,29 @@ public class VibratorManagerServiceTest { private HalVibration vibrateAndWaitUntilFinished(VibratorManagerService service, CombinedVibration effect, VibrationAttributes attrs) throws InterruptedException { - HalVibration vib = - service.vibrateWithPermissionCheck(UID, Context.DEVICE_ID_DEFAULT, PACKAGE_NAME, - effect, attrs, "some reason", service); + HalVibration vib = vibrate(service, effect, attrs); if (vib != null) { vib.waitForEnd(); } - return vib; } - private void vibrate(VibratorManagerService service, VibrationEffect effect, + private HalVibration vibrate(VibratorManagerService service, VibrationEffect effect, VibrationAttributes attrs) { - vibrate(service, CombinedVibration.createParallel(effect), attrs); + return vibrate(service, CombinedVibration.createParallel(effect), attrs); } - private void vibrate(VibratorManagerService service, CombinedVibration effect, + private HalVibration vibrate(VibratorManagerService service, CombinedVibration effect, VibrationAttributes attrs) { - vibrateWithDevice(service, Context.DEVICE_ID_DEFAULT, effect, attrs); + return vibrateWithDevice(service, Context.DEVICE_ID_DEFAULT, effect, attrs); } - private void vibrateWithDevice(VibratorManagerService service, int deviceId, + private HalVibration vibrateWithDevice(VibratorManagerService service, int deviceId, CombinedVibration effect, VibrationAttributes attrs) { - service.vibrate(UID, deviceId, PACKAGE_NAME, effect, attrs, "some reason", service); + HalVibration vib = service.vibrateWithPermissionCheck(UID, deviceId, PACKAGE_NAME, effect, + attrs, "some reason", service); + mPendingVibrations.add(vib); + return vib; } private boolean waitUntil(Predicate<VibratorManagerService> predicate, diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java index 391220669f2f..2a010f0a82a9 100644 --- a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java +++ b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java @@ -18,7 +18,10 @@ package com.android.server.vibrator; import android.annotation.NonNull; import android.frameworks.vibrator.IVibratorController; +import android.frameworks.vibrator.VibrationParam; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.RemoteException; import android.os.VibrationAttributes; @@ -28,17 +31,42 @@ import android.os.VibrationAttributes; */ public final class FakeVibratorController extends IVibratorController.Stub { + private final Handler mHandler; + private VibratorControlService mVibratorControlService; + private VibrationParam[] mRequestResult = new VibrationParam[0]; + public boolean isLinkedToDeath = false; public boolean didRequestVibrationParams = false; public int requestVibrationType = VibrationAttributes.USAGE_UNKNOWN; public long requestTimeoutInMillis = 0; + public FakeVibratorController(Looper looper) { + mHandler = new Handler(looper); + } + + public void setVibratorControlService(VibratorControlService service) { + mVibratorControlService = service; + } + + public void setRequestResult(VibrationParam... params) { + mRequestResult = params; + } + @Override - public void requestVibrationParams(int vibrationType, long timeoutInMillis, IBinder iBinder) + public void requestVibrationParams(int vibrationType, long timeoutInMillis, IBinder token) throws RemoteException { didRequestVibrationParams = true; requestVibrationType = vibrationType; requestTimeoutInMillis = timeoutInMillis; + mHandler.post(() -> { + if (mVibratorControlService != null) { + try { + mVibratorControlService.onRequestVibrationParamsComplete(token, mRequestResult); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + }); } @Override diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp index e83f03d155aa..b2922945aff9 100644 --- a/services/tests/wmtests/Android.bp +++ b/services/tests/wmtests/Android.bp @@ -22,16 +22,21 @@ filegroup { genrule { name: "wmtests.protologsrc", srcs: [ + ":protolog-impl", ":protolog-groups", ":wmtests-sources", ], tools: ["protologtool"], cmd: "$(location protologtool) transform-protolog-calls " + "--protolog-class com.android.internal.protolog.common.ProtoLog " + - "--protolog-impl-class com.android.internal.protolog.ProtoLogImpl " + - "--protolog-cache-class 'com.android.server.wm.ProtoLogCache' " + "--loggroups-class com.android.internal.protolog.ProtoLogGroup " + "--loggroups-jar $(location :protolog-groups) " + + // Used for the ProtoLogIntegrationTest, where don't test decoding or writing to file + // so the parameters below are irrelevant. + "--viewer-config-file-path /some/unused/file/path.pb " + + "--legacy-viewer-config-file-path /some/unused/file/path.json.gz " + + "--legacy-output-file-path /some/unused/file/path.winscope " + + // END of irrelevant params. "--output-srcjar $(out) " + "$(locations :wmtests-sources)", out: ["wmtests.protolog.srcjar"], @@ -42,7 +47,7 @@ android_test { // We only want this apk build for tests. srcs: [ - ":wmtests.protologsrc", + ":wmtests-sources", "src/**/*.aidl", ], diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java index e904eae00802..0a29dfbd7db7 100644 --- a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java @@ -145,7 +145,7 @@ public class ShortcutLoggingTests extends ShortcutKeyTestBase { KeyboardLogEvent.SYSTEM_MUTE, KeyEvent.KEYCODE_MUTE, 0}, {"Meta + Ctrl + DPAD_UP -> Split screen navigation", new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_UP}, - KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION, KeyEvent.KEYCODE_DPAD_UP, + KeyboardLogEvent.MULTI_WINDOW_NAVIGATION, KeyEvent.KEYCODE_DPAD_UP, META_ON | CTRL_ON}, {"Meta + Ctrl + DPAD_LEFT -> Split screen navigation", new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_LEFT}, diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 6132ee3c89c4..173a1b693d87 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -74,7 +74,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -86,9 +85,9 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.notNull; import android.app.ActivityOptions; +import android.app.ActivityOptions.BackgroundActivityStartMode; import android.app.AppOpsManager; import android.app.BackgroundStartPrivileges; -import android.app.ComponentOptions.BackgroundActivityStartMode; import android.app.IApplicationThread; import android.app.PictureInPictureParams; import android.content.ComponentName; diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java index dc4e47dfea30..4060d40865d5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java @@ -20,21 +20,26 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.util.DisplayMetrics.DENSITY_DEFAULT; +import static com.android.server.wm.DesktopModeLaunchParamsModifier.DESKTOP_MODE_INITIAL_BOUNDS_SCALE; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY; +import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_DONE; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; +import android.graphics.Rect; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import com.android.server.wm.LaunchParamsController.LaunchParamsModifier.Result; +import com.android.window.flags.Flags; import org.junit.Before; import org.junit.Test; @@ -69,11 +74,19 @@ public class DesktopModeLaunchParamsModifierTests extends WindowTestsBase { } @Test + @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) + public void testReturnsContinueIfDesktopWindowingIsDisabled() { + assertEquals(RESULT_CONTINUE, new CalculateRequestBuilder().setTask(null).calculate()); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testReturnsSkipIfTaskIsNull() { assertEquals(RESULT_SKIP, new CalculateRequestBuilder().setTask(null).calculate()); } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testReturnsSkipIfNotBoundsPhase() { final Task task = new TaskBuilder(mSupervisor).build(); assertEquals(RESULT_SKIP, new CalculateRequestBuilder().setTask(task).setPhase( @@ -81,6 +94,7 @@ public class DesktopModeLaunchParamsModifierTests extends WindowTestsBase { } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testReturnsSkipIfTaskNotUsingActivityTypeStandardOrUndefined() { final Task task = new TaskBuilder(mSupervisor).setActivityType( ACTIVITY_TYPE_ASSISTANT).build(); @@ -88,6 +102,7 @@ public class DesktopModeLaunchParamsModifierTests extends WindowTestsBase { } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testReturnsDoneIfTaskUsingActivityTypeStandard() { final Task task = new TaskBuilder(mSupervisor).setActivityType( ACTIVITY_TYPE_STANDARD).build(); @@ -95,6 +110,7 @@ public class DesktopModeLaunchParamsModifierTests extends WindowTestsBase { } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testReturnsDoneIfTaskUsingActivityTypeUndefined() { final Task task = new TaskBuilder(mSupervisor).setActivityType( ACTIVITY_TYPE_UNDEFINED).build(); @@ -102,6 +118,7 @@ public class DesktopModeLaunchParamsModifierTests extends WindowTestsBase { } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testReturnsSkipIfCurrentParamsHasBounds() { final Task task = new TaskBuilder(mSupervisor).setActivityType( ACTIVITY_TYPE_STANDARD).build(); @@ -110,15 +127,22 @@ public class DesktopModeLaunchParamsModifierTests extends WindowTestsBase { } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testUsesDefaultBounds() { final Task task = new TaskBuilder(mSupervisor).setActivityType( ACTIVITY_TYPE_STANDARD).build(); + final int displayHeight = 1600; + final int displayWidth = 2560; + task.getDisplayArea().setBounds(new Rect(0, 0, displayWidth, displayHeight)); + final int desiredWidth = (int) (displayWidth * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); + final int desiredHeight = (int) (displayHeight * DESKTOP_MODE_INITIAL_BOUNDS_SCALE); assertEquals(RESULT_DONE, new CalculateRequestBuilder().setTask(task).calculate()); - assertEquals(dpiToPx(task, 840), mResult.mBounds.width()); - assertEquals(dpiToPx(task, 630), mResult.mBounds.height()); + assertEquals(desiredWidth, mResult.mBounds.width()); + assertEquals(desiredHeight, mResult.mBounds.height()); } @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE) public void testUsesDisplayAreaAndWindowingModeFromSource() { final Task task = new TaskBuilder(mSupervisor).setActivityType( ACTIVITY_TYPE_STANDARD).build(); @@ -131,11 +155,6 @@ public class DesktopModeLaunchParamsModifierTests extends WindowTestsBase { assertEquals(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode); } - private int dpiToPx(Task task, int dpi) { - float density = (float) task.getConfiguration().densityDpi / DENSITY_DEFAULT; - return (int) (dpi * density + 0.5f); - } - private class CalculateRequestBuilder { private Task mTask; private int mPhase = PHASE_BOUNDS; diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java index 4c32a586ae78..a0461a6ea9a4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java @@ -42,6 +42,7 @@ import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -541,7 +542,7 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test - public void testUnhandledDragListenerNotCalledForNormalDrags() throws RemoteException { + public void testUnhandledDragNotCalledForNormalDrags() throws RemoteException { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); @@ -552,15 +553,16 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test - public void testUnhandledDragListenerReceivesUnhandledDropOverWindow() { + public void testUnhandledDragReceivesUnhandledDropOverWindow() { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); doReturn(mock(Binder.class)).when(listener).asBinder(); mTarget.setGlobalDragListener(listener); final int invalidXY = 100_000; - startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { - // Notify the unhandled drag listener + startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, + ClipData.newPlainText("label", "Test"), () -> { + // Trigger an unhandled drop and verify the global drag listener was called mTarget.reportDropWindow(mWindow.mInputChannelToken, invalidXY, invalidXY); mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); mTarget.reportDropResult(mWindow.mClient, false); @@ -575,15 +577,16 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test - public void testUnhandledDragListenerReceivesUnhandledDropOverNoValidWindow() { + public void testUnhandledDragReceivesUnhandledDropOverNoValidWindow() { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); doReturn(mock(Binder.class)).when(listener).asBinder(); mTarget.setGlobalDragListener(listener); final int invalidXY = 100_000; - startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { - // Notify the unhandled drag listener + startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, + ClipData.newPlainText("label", "Test"), () -> { + // Trigger an unhandled drop and verify the global drag listener was called mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); mTarget.onUnhandledDropCallback(true); @@ -597,15 +600,38 @@ public class DragDropControllerTests extends WindowTestsBase { } @Test - public void testUnhandledDragListenerCallbackTimeout() { + public void testUnhandledDragDoesNotReceiveUnhandledDropWithoutDragFlag() { assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); final IGlobalDragListener listener = mock(IGlobalDragListener.class); doReturn(mock(Binder.class)).when(listener).asBinder(); mTarget.setGlobalDragListener(listener); final int invalidXY = 100_000; - startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> { - // Notify the unhandled drag listener + startDrag(View.DRAG_FLAG_GLOBAL, + ClipData.newPlainText("label", "Test"), () -> { + // Trigger an unhandled drop and verify the global drag listener was not called + mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); + mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); + mToken = null; + try { + verify(listener, never()).onUnhandledDrop(any(), any()); + } catch (RemoteException e) { + fail("Failed to verify unhandled drop: " + e); + } + }); + } + + @Test + public void testUnhandledDragCallbackTimeout() { + assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags()); + + final IGlobalDragListener listener = mock(IGlobalDragListener.class); + doReturn(mock(Binder.class)).when(listener).asBinder(); + mTarget.setGlobalDragListener(listener); + final int invalidXY = 100_000; + startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, + ClipData.newPlainText("label", "Test"), () -> { + // Trigger an unhandled drop and verify the global drag listener was called mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY); mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY); diff --git a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java index af0d32c764a4..c5bf78bb60b5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java @@ -27,6 +27,8 @@ import androidx.test.filters.SmallTest; import com.android.internal.protolog.ProtoLogGroup; import com.android.internal.protolog.ProtoLogImpl; +import com.android.internal.protolog.common.IProtoLog; +import com.android.internal.protolog.common.LogLevel; import com.android.internal.protolog.common.ProtoLog; import org.junit.After; @@ -47,9 +49,9 @@ public class ProtoLogIntegrationTest { @Ignore("b/163095037") @Test public void testProtoLogToolIntegration() { - ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class); + IProtoLog mockedProtoLog = mock(IProtoLog.class); runWith(mockedProtoLog, this::testProtoLog); - verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.ERROR), eq(ProtoLogGroup.TEST_GROUP), + verify(mockedProtoLog).log(eq(LogLevel.ERROR), eq(ProtoLogGroup.TEST_GROUP), anyInt(), eq(0b0010010111), eq(com.android.internal.protolog.ProtoLogGroup.TEST_GROUP.isLogToLogcat() ? "Test completed successfully: %b %d %x %f %% %s" @@ -66,18 +68,13 @@ public class ProtoLogIntegrationTest { /** * Starts protolog for the duration of {@code runnable}, with a ProtoLogImpl instance installed. */ - private void runWith(ProtoLogImpl mockInstance, Runnable runnable) { - ProtoLogImpl original = ProtoLogImpl.getSingleInstance(); - original.startProtoLog(null); + private void runWith(IProtoLog mockInstance, Runnable runnable) { + IProtoLog original = ProtoLog.getSingleInstance(); + ProtoLogImpl.setSingleInstance(mockInstance); try { - ProtoLogImpl.setSingleInstance(mockInstance); - try { - runnable.run(); - } finally { - ProtoLogImpl.setSingleInstance(original); - } + runnable.run(); } finally { - original.stopProtoLog(null, false); + ProtoLogImpl.setSingleInstance(original); } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index 9930c88b1e48..f7c253d9df03 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -46,7 +46,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; @@ -73,6 +72,7 @@ import android.os.SystemClock; import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; +import android.util.IntArray; import android.util.SparseBooleanArray; import android.view.Surface; import android.window.TaskSnapshot; @@ -527,20 +527,20 @@ public class RecentTasksTest extends WindowTestsBase { mTaskPersister.mUserTaskIdsOverride.put(1, true); mTaskPersister.mUserTaskIdsOverride.put(2, true); mTaskPersister.mUserTasksOverride = new ArrayList<>(); - mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build()); - mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build()); + mTaskPersister.mUserTasksOverride.add(mTasks.get(0)); + mTaskPersister.mUserTasksOverride.add(mTasks.get(1)); // Assert no user tasks are initially loaded assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0); // Load user 0 tasks - mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID); + mRecentTasks.loadRecentTasksIfNeeded(TEST_USER_0_ID); assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID); assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID)); assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID)); // Load user 1 tasks - mRecentTasks.loadUserRecentsLocked(TEST_USER_1_ID); + mRecentTasks.loadRecentTasksIfNeeded(TEST_USER_1_ID); assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID); assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_1_ID); assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID)); @@ -575,15 +575,15 @@ public class RecentTasksTest extends WindowTestsBase { mTaskPersister.mUserTaskIdsOverride.put(2, true); mTaskPersister.mUserTaskIdsOverride.put(3, true); mTaskPersister.mUserTasksOverride = new ArrayList<>(); - mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build()); - mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build()); - mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask3").build()); + mTaskPersister.mUserTasksOverride.add(mTasks.get(0)); + mTaskPersister.mUserTasksOverride.add(mTasks.get(1)); + mTaskPersister.mUserTasksOverride.add(mTasks.get(2)); // Assert no user tasks are initially loaded assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0); // Load tasks - mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID); + mRecentTasks.loadRecentTasksIfNeeded(TEST_USER_0_ID); assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID); // Sort the time descendingly so the order should be in-sync with task recency (most @@ -1419,8 +1419,6 @@ public class RecentTasksTest extends WindowTestsBase { } private List<RecentTaskInfo> getRecentTasks(int flags) { - doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt()); - doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt()); return mRecentTasks.getRecentTasks(MAX_VALUE, flags, true /* getTasksAllowed */, TEST_USER_0_ID, 0 /* callingUid */).getList(); } @@ -1590,19 +1588,20 @@ public class RecentTasksTest extends WindowTestsBase { } @Override - SparseBooleanArray loadPersistedTaskIdsForUser(int userId) { + SparseBooleanArray readPersistedTaskIdsFromFileForUser(int userId) { if (mUserTaskIdsOverride != null) { return mUserTaskIdsOverride; } - return super.loadPersistedTaskIdsForUser(userId); + return super.readPersistedTaskIdsFromFileForUser(userId); } @Override - List<Task> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) { + ArrayList<Task> restoreTasksForUserLocked(int userId, RecentTaskFiles recentTaskFiles, + IntArray existedTaskIds) { if (mUserTasksOverride != null) { return mUserTasksOverride; } - return super.restoreTasksForUserLocked(userId, preaddedTasks); + return super.restoreTasksForUserLocked(userId, recentTaskFiles, existedTaskIds); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java index 12ed3c28161f..319be89b2901 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java @@ -29,8 +29,6 @@ import android.os.UserManager; import android.platform.test.annotations.Presubmit; import android.util.SparseBooleanArray; -import androidx.test.filters.FlakyTest; - import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -81,7 +79,7 @@ public class TaskPersisterTest { } mTaskPersister.writePersistedTaskIdsForUser(taskIdsOnFile, mTestUserId); SparseBooleanArray newTaskIdsOnFile = mTaskPersister - .loadPersistedTaskIdsForUser(mTestUserId); + .readPersistedTaskIdsFromFileForUser(mTestUserId); assertEquals("TaskIds written differ from TaskIds read back from file", taskIdsOnFile, newTaskIdsOnFile); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java index a0e64bf94393..12f46df451fe 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java @@ -82,7 +82,10 @@ import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.util.ArraySet; import android.util.MergedConfiguration; import android.view.ContentRecordingSession; @@ -109,6 +112,7 @@ import com.android.internal.os.IResultReceiver; import com.android.server.LocalServices; import com.android.server.wm.SensitiveContentPackages.PackageInfo; import com.android.server.wm.WindowManagerService.WindowContainerInfo; +import com.android.window.flags.Flags; import com.google.common.truth.Expect; @@ -140,6 +144,9 @@ public class WindowManagerServiceTests extends WindowTestsBase { @Rule public Expect mExpect = Expect.create(); + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @After public void tearDown() { mWm.mSensitiveContentPackages.clearBlockedApps(); @@ -1106,6 +1113,7 @@ public class WindowManagerServiceTests extends WindowTestsBase { argThat(h -> (h.inputConfig & InputConfig.SPY) == InputConfig.SPY)); } + @RequiresFlagsDisabled(Flags.FLAG_MAGNIFICATION_ALWAYS_DRAW_FULLSCREEN_BORDER) @Test public void testDrawMagnifiedViewport() { final int displayId = mDisplayContent.mDisplayId; diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java index 0a1f3c78e0e6..ad7b9e69282e 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java @@ -411,7 +411,8 @@ abstract class DetectorSession { audioFormat, options, callback, - /* shouldCloseAudioStreamWithDelayOnDetect= */ true); + /* shouldCloseAudioStreamWithDelayOnDetect= */ true, + /* shouldCheckPermissionsAndAppOpsOnDetected= */ true); } void startListeningFromWearableLocked( @@ -481,12 +482,29 @@ abstract class DetectorSession { return null; } }; + /* + * By setting shouldCheckPermissionsAndAppOpsOnDetected to false, when the audio + * stream is sent from the sandboxed HotwordDetectionService to the non-sandboxed + * VoiceInteractionService as a result of second-stage hotword detection, audio-related + * permissions will not be checked against the VoiceInteractionService and the AppOpsManager + * will not be notified of the data flow to the VoiceInteractionService. These checks are + * not performed because the audio stream here originates from a remotely connected wearable + * device. It does not originate from the microphone of the device where this code runs on, + * or a microphone directly controlled by this system. Permission checks are expected to + * happen on the remote wearable device. From the perspective of this system, the audio + * stream is data received from an external source. + * + * Not notifying AppOpsManager allows this device's microphone indicator to remain off when + * this data flow happens. It avoids confusion since the audio does not originate from + * this device. The wearable is expected to turn on its own microphone indicator. + */ handleExternalSourceHotwordDetectionLocked( audioStream, audioFormat, options, voiceInteractionCallback, - /* shouldCloseAudioStreamWithDelayOnDetect= */ false); + /* shouldCloseAudioStreamWithDelayOnDetect= */ false, + /* shouldCheckPermissionsAndAppOpsOnDetected= */ false); } @SuppressWarnings("GuardedBy") @@ -495,7 +513,8 @@ abstract class DetectorSession { AudioFormat audioFormat, @Nullable PersistableBundle options, IMicrophoneHotwordDetectionVoiceInteractionCallback callback, - boolean shouldCloseAudioStreamWithDelayOnDetect) { + boolean shouldCloseAudioStreamWithDelayOnDetect, + boolean shouldCheckPermissionsAndAppOpsOnDetected) { if (DEBUG) { Slog.d(TAG, "#handleExternalSourceHotwordDetectionLocked"); } @@ -631,36 +650,39 @@ abstract class DetectorSession { EXTERNAL_HOTWORD_CLEANUP_MILLIS, TimeUnit.MILLISECONDS); } - try { - enforcePermissionsForDataDelivery(); - } catch (SecurityException e) { - Slog.w( - TAG, - "Ignoring #onDetected due to a " - + "SecurityException", - e); - HotwordMetricsLogger.writeDetectorEvent( - getDetectorType(), - EXTERNAL_SOURCE_DETECT_SECURITY_EXCEPTION, - mVoiceInteractionServiceUid); + if (shouldCheckPermissionsAndAppOpsOnDetected) { try { - callback.onHotwordDetectionServiceFailure( + enforcePermissionsForDataDelivery(); + } catch (SecurityException e) { + Slog.w( + TAG, + "Ignoring #onDetected due to a " + + "SecurityException", + e); + HotwordMetricsLogger.writeDetectorEvent( + getDetectorType(), + EXTERNAL_SOURCE_DETECT_SECURITY_EXCEPTION, + mVoiceInteractionServiceUid); + try { + callback.onHotwordDetectionServiceFailure( new HotwordDetectionServiceFailure( ONDETECTED_GOT_SECURITY_EXCEPTION, "Security exception occurs in " + "#onDetected method")); - } catch (RemoteException e1) { - notifyOnDetectorRemoteException(); - throw e1; + } catch (RemoteException e1) { + notifyOnDetectorRemoteException(); + throw e1; + } + return; } - return; } HotwordDetectedResult newResult; try { newResult = - mHotwordAudioStreamCopier - .startCopyingAudioStreams( - triggerResult); + mHotwordAudioStreamCopier + .startCopyingAudioStreams( + triggerResult, + shouldCheckPermissionsAndAppOpsOnDetected); } catch (IOException e) { Slog.w( TAG, diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java index 65c95d1261f3..6f00dc82f42b 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java @@ -87,18 +87,31 @@ final class HotwordAudioStreamCopier { } /** + * Calls {@link #startCopyingAudioStreams(HotwordDetectedResult, boolean)} and notifies + * AppOpsManager of the {@link AppOpsManager#OPSTR_RECORD_AUDIO_HOTWORD} operation. + */ + @NonNull + public HotwordDetectedResult startCopyingAudioStreams(@NonNull HotwordDetectedResult result) + throws IOException { + return startCopyingAudioStreams(result, /* shouldNotifyAppOpsManager= */ true); + } + + /** * Starts copying the audio streams in the given {@link HotwordDetectedResult}. - * <p> - * The returned {@link HotwordDetectedResult} is identical the one that was passed in, except + * + * <p>The returned {@link HotwordDetectedResult} is identical the one that was passed in, except * that the {@link ParcelFileDescriptor}s within {@link HotwordDetectedResult#getAudioStreams()} * are replaced with descriptors from pipes managed by {@link HotwordAudioStreamCopier}. The * returned value should be passed on to the client (i.e., the voice interactor). - * </p> * + * @param result The {@link HotwordDetectedResult} to copy from. + * @param shouldNotifyAppOpsManager Whether the {@link AppOpsManager} should be notified of the + * {@link AppOpsManager#OPSTR_RECORD_AUDIO_HOTWORD} operation during the copy. * @throws IOException If there was an error creating the managed pipe. */ @NonNull - public HotwordDetectedResult startCopyingAudioStreams(@NonNull HotwordDetectedResult result) + public HotwordDetectedResult startCopyingAudioStreams( + @NonNull HotwordDetectedResult result, boolean shouldNotifyAppOpsManager) throws IOException { List<HotwordAudioStream> audioStreams = result.getAudioStreams(); if (audioStreams.isEmpty()) { @@ -154,8 +167,12 @@ final class HotwordAudioStreamCopier { String resultTaskId = TASK_ID_PREFIX + System.identityHashCode(result); mExecutorService.execute( - new HotwordDetectedResultCopyTask(resultTaskId, copyTaskInfos, - totalMetadataBundleSizeBytes, totalInitialAudioSizeBytes)); + new HotwordDetectedResultCopyTask( + resultTaskId, + copyTaskInfos, + totalMetadataBundleSizeBytes, + totalInitialAudioSizeBytes, + shouldNotifyAppOpsManager)); return result.buildUpon().setAudioStreams(newAudioStreams).build(); } @@ -178,13 +195,19 @@ final class HotwordAudioStreamCopier { private final int mTotalMetadataSizeBytes; private final int mTotalInitialAudioSizeBytes; private final ExecutorService mExecutorService = Executors.newCachedThreadPool(); - - HotwordDetectedResultCopyTask(String resultTaskId, List<CopyTaskInfo> copyTaskInfos, - int totalMetadataSizeBytes, int totalInitialAudioSizeBytes) { + private final boolean mShouldNotifyAppOpsManager; + + HotwordDetectedResultCopyTask( + String resultTaskId, + List<CopyTaskInfo> copyTaskInfos, + int totalMetadataSizeBytes, + int totalInitialAudioSizeBytes, + boolean shouldNotifyAppOpsManager) { mResultTaskId = resultTaskId; mCopyTaskInfos = copyTaskInfos; mTotalMetadataSizeBytes = totalMetadataSizeBytes; mTotalInitialAudioSizeBytes = totalInitialAudioSizeBytes; + mShouldNotifyAppOpsManager = shouldNotifyAppOpsManager; } @Override @@ -200,55 +223,14 @@ final class HotwordAudioStreamCopier { mVoiceInteractorUid)); } - if (mAppOpsManager.startOpNoThrow(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD, - mVoiceInteractorUid, mVoiceInteractorPackageName, - mVoiceInteractorAttributionTag, OP_MESSAGE) == MODE_ALLOWED) { - try { - HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, - HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__STARTED, - mVoiceInteractorUid, mTotalInitialAudioSizeBytes, - mTotalMetadataSizeBytes, size); - // TODO(b/244599891): Set timeout, close after inactivity - mExecutorService.invokeAll(tasks); - - // We are including the non-streamed initial audio - // (HotwordAudioStream.getInitialAudio()) bytes in the "stream" size metrics. - int totalStreamSizeBytes = mTotalInitialAudioSizeBytes; - for (SingleAudioStreamCopyTask task : tasks) { - totalStreamSizeBytes += task.mTotalCopiedBytes; - } - - Slog.i(TAG, mResultTaskId + ": Task was completed. Total bytes egressed: " - + totalStreamSizeBytes + " (including " + mTotalInitialAudioSizeBytes - + " bytes NOT streamed), total metadata bundle size bytes: " - + mTotalMetadataSizeBytes); - HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, - HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ENDED, - mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes, - size); - } catch (InterruptedException e) { - // We are including the non-streamed initial audio - // (HotwordAudioStream.getInitialAudio()) bytes in the "stream" size metrics. - int totalStreamSizeBytes = mTotalInitialAudioSizeBytes; - for (SingleAudioStreamCopyTask task : tasks) { - totalStreamSizeBytes += task.mTotalCopiedBytes; - } - - HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, - HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION, - mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes, - size); - Slog.i(TAG, mResultTaskId + ": Task was interrupted. Total bytes egressed: " - + totalStreamSizeBytes + " (including " + mTotalInitialAudioSizeBytes - + " bytes NOT streamed), total metadata bundle size bytes: " - + mTotalMetadataSizeBytes); - bestEffortPropagateError(e.getMessage()); - } finally { - mAppOpsManager.finishOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD, - mVoiceInteractorUid, mVoiceInteractorPackageName, - mVoiceInteractorAttributionTag); - } - } else { + if (mShouldNotifyAppOpsManager + && mAppOpsManager.startOpNoThrow( + AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD, + mVoiceInteractorUid, + mVoiceInteractorPackageName, + mVoiceInteractorAttributionTag, + OP_MESSAGE) + != MODE_ALLOWED) { HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__NO_PERMISSION, mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0, @@ -258,6 +240,56 @@ final class HotwordAudioStreamCopier { + " uid=" + mVoiceInteractorUid + " packageName=" + mVoiceInteractorPackageName + " attributionTag=" + mVoiceInteractorAttributionTag); + return; + } + try { + HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__STARTED, + mVoiceInteractorUid, mTotalInitialAudioSizeBytes, + mTotalMetadataSizeBytes, size); + // TODO(b/244599891): Set timeout, close after inactivity + mExecutorService.invokeAll(tasks); + + // We are including the non-streamed initial audio + // (HotwordAudioStream.getInitialAudio()) bytes in the "stream" size metrics. + int totalStreamSizeBytes = mTotalInitialAudioSizeBytes; + for (SingleAudioStreamCopyTask task : tasks) { + totalStreamSizeBytes += task.mTotalCopiedBytes; + } + + Slog.i(TAG, mResultTaskId + ": Task was completed. Total bytes egressed: " + + totalStreamSizeBytes + " (including " + mTotalInitialAudioSizeBytes + + " bytes NOT streamed), total metadata bundle size bytes: " + + mTotalMetadataSizeBytes); + HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ENDED, + mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes, + size); + } catch (InterruptedException e) { + // We are including the non-streamed initial audio + // (HotwordAudioStream.getInitialAudio()) bytes in the "stream" size metrics. + int totalStreamSizeBytes = mTotalInitialAudioSizeBytes; + for (SingleAudioStreamCopyTask task : tasks) { + totalStreamSizeBytes += task.mTotalCopiedBytes; + } + + HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType, + HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION, + mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes, + size); + Slog.i(TAG, mResultTaskId + ": Task was interrupted. Total bytes egressed: " + + totalStreamSizeBytes + " (including " + mTotalInitialAudioSizeBytes + + " bytes NOT streamed), total metadata bundle size bytes: " + + mTotalMetadataSizeBytes); + bestEffortPropagateError(e.getMessage()); + } finally { + if (mShouldNotifyAppOpsManager) { + mAppOpsManager.finishOp( + AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD, + mVoiceInteractorUid, + mVoiceInteractorPackageName, + mVoiceInteractorAttributionTag); + } } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index c217780d90d6..aef7158fd613 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -16,15 +16,21 @@ package com.android.server.voiceinteraction; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; +import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION; import android.Manifest; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerInternal; +import android.app.ActivityOptions; import android.app.AppGlobals; +import android.app.admin.DevicePolicyManagerInternal; import android.app.role.OnRoleHoldersChangedListener; import android.app.role.RoleManager; import android.content.ComponentName; @@ -41,6 +47,7 @@ import android.content.pm.ShortcutServiceInternal; import android.content.pm.UserInfo; import android.content.res.Resources; import android.database.ContentObserver; +import android.graphics.Bitmap; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.KeyphraseMetadata; import android.hardware.soundtrigger.ModelParams; @@ -84,6 +91,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.Slog; +import android.window.ScreenCapture; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; @@ -110,7 +118,9 @@ import com.android.server.pm.permission.LegacyPermissionManagerInternal; import com.android.server.policy.AppOpsPolicy; import com.android.server.utils.Slogf; import com.android.server.utils.TimingsTraceAndSlog; +import com.android.server.wm.ActivityAssistInfo; import com.android.server.wm.ActivityTaskManagerInternal; +import com.android.server.wm.WindowManagerInternal; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -127,6 +137,19 @@ public class VoiceInteractionManagerService extends SystemService { static final String TAG = "VoiceInteractionManager"; static final boolean DEBUG = false; + /** Static constants used by Contextual Search helper. */ + private static final String CS_KEY_FLAG_SECURE_FOUND = + "com.android.contextualsearch.flag_secure_found"; + private static final String CS_KEY_FLAG_SCREENSHOT = + "com.android.contextualsearch.screenshot"; + private static final String CS_KEY_FLAG_IS_MANAGED_PROFILE_VISIBLE = + "com.android.contextualsearch.is_managed_profile_visible"; + private static final String CS_KEY_FLAG_VISIBLE_PACKAGE_NAMES = + "com.android.contextualsearch.visible_package_names"; + private static final String CS_INTENT_FILTER = + "com.android.contextualsearch.LAUNCH"; + + final Context mContext; final ContentResolver mResolver; // Can be overridden for testing purposes @@ -135,6 +158,8 @@ public class VoiceInteractionManagerService extends SystemService { final ActivityManagerInternal mAmInternal; final ActivityTaskManagerInternal mAtmInternal; final UserManagerInternal mUserManagerInternal; + final WindowManagerInternal mWmInternal; + final DevicePolicyManagerInternal mDpmInternal; final ArrayMap<Integer, VoiceInteractionManagerServiceStub.SoundTriggerSession> mLoadedKeyphraseIds = new ArrayMap<>(); ShortcutServiceInternal mShortcutServiceInternal; @@ -156,7 +181,10 @@ public class VoiceInteractionManagerService extends SystemService { LocalServices.getService(ActivityManagerInternal.class)); mAtmInternal = Objects.requireNonNull( LocalServices.getService(ActivityTaskManagerInternal.class)); - + mWmInternal = Objects.requireNonNull( + LocalServices.getService(WindowManagerInternal.class)); + mDpmInternal = Objects.requireNonNull( + LocalServices.getService(DevicePolicyManagerInternal.class)); LegacyPermissionManagerInternal permissionManagerInternal = LocalServices.getService( LegacyPermissionManagerInternal.class); permissionManagerInternal.setVoiceInteractionPackagesProvider( @@ -1019,6 +1047,56 @@ public class VoiceInteractionManagerService extends SystemService { public boolean showSessionFromSession(@NonNull IBinder token, @Nullable Bundle sessionArgs, int flags, @Nullable String attributionTag) { synchronized (this) { + final String csKey = mContext.getResources() + .getString(R.string.config_defaultContextualSearchKey); + final String csEnabledKey = mContext.getResources() + .getString(R.string.config_defaultContextualSearchEnabled); + + // If the request is for Contextual Search, process it differently + if (sessionArgs != null && sessionArgs.containsKey(csKey)) { + if (sessionArgs.getBoolean(csEnabledKey, true)) { + // If Contextual Search is enabled, try to follow that path. + Intent launchIntent = getContextualSearchIntent(sessionArgs); + if (launchIntent != null) { + // Hand over to contextual search helper. + Slog.d(TAG, "Handed over to contextual search helper."); + final long caller = Binder.clearCallingIdentity(); + try { + return startContextualSearch(launchIntent); + } finally { + Binder.restoreCallingIdentity(caller); + } + } + } + + // Since we are here, Contextual Search helper couldn't handle the request. + final String visEnabledKey = mContext.getResources() + .getString(R.string.config_defaultContextualSearchLegacyEnabled); + if (sessionArgs.getBoolean(visEnabledKey, true)) { + // If visEnabledKey is set to true (or absent), we try following VIS path. + String csPkgName = mContext.getResources() + .getString(R.string.config_defaultContextualSearchPackageName); + if (!csPkgName.equals(getCurInteractor( + Binder.getCallingUserHandle().getIdentifier()).getPackageName())) { + // Check if the interactor can handle Contextual Search. + // If not, return failure. + Slog.w(TAG, "Contextual Search not supported yet. Returning failure."); + return false; + } + } else { + // If visEnabledKey is set to false AND the request was for Contextual + // Search, return false. + return false; + } + // Given that we haven't returned yet, we can say that + // - Contextual Search Helper couldn't handle the request + // - VIS path for Contextual Search is enabled + // - The current interactor supports Contextual Search. + // Hence, we will proceed with the VIS path. + Slog.d(TAG, "Contextual search not supported yet. Proceeding with VIS."); + + } + if (mImpl == null) { Slog.w(TAG, "showSessionFromSession without running voice interaction service"); return false; @@ -2644,6 +2722,70 @@ public class VoiceInteractionManagerService extends SystemService { } } }; + + private Intent getContextualSearchIntent(Bundle args) { + String csPkgName = mContext.getResources() + .getString(R.string.config_defaultContextualSearchPackageName); + if (csPkgName.isEmpty()) { + // Return null if csPackageName is not specified. + return null; + } + Intent launchIntent = new Intent(CS_INTENT_FILTER); + launchIntent.setPackage(csPkgName); + ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity( + launchIntent, PackageManager.MATCH_FACTORY_ONLY); + if (resolveInfo == null) { + return null; + } + launchIntent.setComponent(resolveInfo.getComponentInfo().getComponentName()); + launchIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION + | FLAG_ACTIVITY_NO_USER_ACTION); + launchIntent.putExtras(args); + boolean isAssistDataAllowed = mAtmInternal.isAssistDataAllowed(); + final List<ActivityAssistInfo> records = mAtmInternal.getTopVisibleActivities(); + ArrayList<String> visiblePackageNames = new ArrayList<>(); + boolean isManagedProfileVisible = false; + for (ActivityAssistInfo record: records) { + // Add the package name to the list only if assist data is allowed. + if (isAssistDataAllowed) { + visiblePackageNames.add(record.getComponentName().getPackageName()); + } + if (mDpmInternal.isUserOrganizationManaged(record.getUserId())) { + isManagedProfileVisible = true; + } + } + final ScreenCapture.ScreenshotHardwareBuffer shb = mWmInternal.takeAssistScreenshot(); + final Bitmap bm = shb != null ? shb.asBitmap() : null; + // Now that everything is fetched, putting it in the launchIntent. + if (bm != null) { + launchIntent.putExtra(CS_KEY_FLAG_SECURE_FOUND, shb.containsSecureLayers()); + // Only put the screenshot if assist data is allowed + if (isAssistDataAllowed) { + launchIntent.putExtra(CS_KEY_FLAG_SCREENSHOT, bm.asShared()); + } + } + launchIntent.putExtra(CS_KEY_FLAG_IS_MANAGED_PROFILE_VISIBLE, isManagedProfileVisible); + // Only put the list of visible package names if assist data is allowed + if (isAssistDataAllowed) { + launchIntent.putExtra(CS_KEY_FLAG_VISIBLE_PACKAGE_NAMES, visiblePackageNames); + } + + return launchIntent; + } + + @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS) + private boolean startContextualSearch(Intent launchIntent) { + // Contextual search starts with a frozen screen - so we launch without + // any system animations or starting window. + final ActivityOptions opts = ActivityOptions.makeCustomTaskAnimation(mContext, + /* enterResId= */ 0, /* exitResId= */ 0, null, null, null); + opts.setDisableStartingWindow(true); + int resultCode = mAtmInternal.startActivityWithScreenshot(launchIntent, + mContext.getPackageName(), Binder.getCallingUid(), Binder.getCallingPid(), null, + opts.toBundle(), Binder.getCallingUserHandle().getIdentifier()); + return resultCode == ActivityManager.START_SUCCESS; + } + } /** diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java index 217659ee4345..700856c50bae 100644 --- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java +++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java @@ -726,7 +726,7 @@ public class GraphicsActivity extends Activity { .map(Object::toString) .collect(Collectors.joining(", "))); int initialNumEvents = mModeChangedEvents.size(); - surface.setFrameRate(30.f, compatibility); + surface.setFrameRate(70.f, compatibility); verifyFrameRates(expectedFrameRates, surface); verifyModeSwitchesDontChangeResolution(initialNumEvents, mModeChangedEvents.size()); }); @@ -824,7 +824,7 @@ public class GraphicsActivity extends Activity { Display display = getDisplay(); List<Float> expectedFrameRates = getRefreshRates(display.getMode(), display) .stream() - .filter(rate -> rate >= 30.f) + .filter(rate -> rate >= 70.f) .collect(Collectors.toList()); assumeTrue("**** testSurfaceControlFrameRateCompatibility SKIPPED because no refresh rate " diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt index 6209a0838d9b..ad39fa99c85b 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt @@ -17,8 +17,8 @@ package com.android.server.wm.flicker.activityembedding import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper import org.junit.Before diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt index 0c36c59a8a83..46ad77e1eff9 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt @@ -17,12 +17,12 @@ package com.android.server.wm.flicker.activityembedding.close import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.Rect -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.datatypes.Rect +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt index 955e801e7e0a..af4f7a721464 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt @@ -17,11 +17,11 @@ package com.android.server.wm.flicker.activityembedding.layoutchange import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.Rect -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.datatypes.Rect +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt index ce9c337ff9bd..e511b727d57f 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt @@ -17,11 +17,11 @@ package com.android.server.wm.flicker.activityembedding.open import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.Rect -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.datatypes.Rect +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt index 59ff0c65c4fc..5009c7ce4e70 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.activityembedding.open import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt index 365782012c54..000b457026be 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt @@ -17,11 +17,11 @@ package com.android.server.wm.flicker.activityembedding.open import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt index 9f9fc23081c5..4352177a8984 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt @@ -17,11 +17,11 @@ package com.android.server.wm.flicker.activityembedding.open import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.Rect -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.datatypes.Rect +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt index 30e833f433a8..62cf6cd528e9 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt @@ -17,12 +17,12 @@ package com.android.server.wm.flicker.activityembedding.open import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.Rect -import android.tools.common.flicker.subject.region.RegionSubject -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.datatypes.Rect +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.subject.region.RegionSubject import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt index c8cac8fa2c82..aa8b4cebe91d 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt @@ -17,14 +17,14 @@ package com.android.server.wm.flicker.activityembedding.pip import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.Rect -import android.tools.common.flicker.subject.layers.LayersTraceSubject -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.common.traces.component.ComponentNameMatcher.Companion.TRANSITION_SNAPSHOT -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.datatypes.Rect +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.subject.layers.LayersTraceSubject +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.component.ComponentNameMatcher.Companion.TRANSITION_SNAPSHOT import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase @@ -176,9 +176,7 @@ class SecondaryActivityEnterPipTest(flicker: LegacyFlickerTest) : val secondaryVisibleRegion = it.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT) if (secondaryVisibleRegion.region.isNotEmpty) { - check { "left" } - .that(secondaryVisibleRegion.region.bounds.left) - .isGreater(0) + check { "left" }.that(secondaryVisibleRegion.region.bounds.left).isGreater(0) } } } @@ -217,7 +215,7 @@ class SecondaryActivityEnterPipTest(flicker: LegacyFlickerTest) : flicker.assertLayers { visibleLayersShownMoreThanOneConsecutiveEntry( LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS + - listOf(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) + listOf(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT) ) } } diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt index 0dce870966d7..3d834c16163f 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt @@ -17,11 +17,11 @@ package com.android.server.wm.flicker.activityembedding.rotation import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt index f6d51f981915..511c94849681 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.activityembedding.rotation import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase import com.android.server.wm.flicker.helpers.setRotation import org.junit.Test diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt index 6be78f829b34..65a23e854e0b 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.activityembedding.rtl import android.platform.test.annotations.Presubmit -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt index 576eec847066..7298e5f71b05 100644 --- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt +++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt @@ -18,12 +18,12 @@ package com.android.server.wm.flicker.activityembedding.splitscreen import android.platform.test.annotations.Presubmit import android.platform.test.annotations.RequiresDevice -import android.tools.common.datatypes.Rect -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.datatypes.Rect +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt index 64dd44d8b6e0..e19e1ce35cd9 100644 --- a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt +++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt @@ -16,11 +16,11 @@ package com.android.server.wm.flicker.close -import android.tools.common.flicker.annotation.FlickerServiceCompatible -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.annotation.FlickerServiceCompatible +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import org.junit.FixMethodOrder import org.junit.Test diff --git a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt index eb256b56193d..47ed642cd5f5 100644 --- a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt +++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt @@ -16,11 +16,11 @@ package com.android.server.wm.flicker.close -import android.tools.common.flicker.annotation.FlickerServiceCompatible -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.annotation.FlickerServiceCompatible +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import org.junit.FixMethodOrder import org.junit.Test diff --git a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt index ea025c74b8db..65bc35641128 100644 --- a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt +++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt @@ -17,12 +17,12 @@ package com.android.server.wm.flicker.close import android.platform.test.annotations.Presubmit -import android.tools.common.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.component.ComponentNameMatcher.Companion.LAUNCHER import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.SimpleAppHelper diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt index 89ab41e49270..ffa90a33e7b3 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt @@ -17,12 +17,12 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt index 413767ce7618..8c285bda6616 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt @@ -16,9 +16,9 @@ package com.android.server.wm.flicker.launch -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.launch.common.OpenAppFromIconTransition import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt index 4168bdc705f1..d47329ea97b4 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.launch import android.tools.device.apphelpers.CameraAppHelper -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition import org.junit.FixMethodOrder import org.junit.runner.RunWith diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt index 9c55c98a8f4f..267f282db41c 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt @@ -18,12 +18,12 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.flicker.annotation.FlickerServiceCompatible -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome +import android.tools.flicker.annotation.FlickerServiceCompatible +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt index fc6cdb1ee01e..83065de8b592 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt @@ -17,11 +17,11 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.Presubmit -import android.tools.common.flicker.annotation.FlickerServiceCompatible -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.annotation.FlickerServiceCompatible +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt index de666dd42877..44ae27c2ee4b 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt @@ -17,13 +17,13 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.annotation.FlickerServiceCompatible -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.annotation.FlickerServiceCompatible +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.NonResizeableAppHelper diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt index f8a9961d1d28..6d3eaeb9c1b3 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt @@ -17,12 +17,12 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.flicker.annotation.FlickerServiceCompatible -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.annotation.FlickerServiceCompatible +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt index 0aceb354dec6..bec02d0e59c6 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt @@ -18,15 +18,15 @@ package com.android.server.wm.flicker.launch import android.os.SystemClock import android.platform.test.annotations.Postsubmit -import android.tools.common.flicker.subject.layers.LayersTraceSubject -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.CameraAppHelper import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.rules.RemoveAllTasksButHomeRule +import android.tools.flicker.subject.layers.LayersTraceSubject +import android.tools.traces.component.ComponentNameMatcher import android.view.KeyEvent import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.setRotation diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt index f41a2a297ad9..e0aef8d1addd 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.launch import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.TransferSplashscreenAppHelper diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt index 93ca41c4181c..f1144991c438 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt @@ -20,15 +20,15 @@ import android.app.Instrumentation import android.os.Bundle import android.os.Handler import android.platform.test.annotations.Presubmit -import android.tools.common.traces.ConditionsFactory -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerBuilderProvider -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule -import android.tools.device.helpers.wakeUpAndGoToHomeScreen +import android.tools.flicker.junit.FlickerBuilderProvider +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.rules.RemoveAllTasksButHomeRule +import android.tools.helpers.wakeUpAndGoToHomeScreen +import android.tools.traces.ConditionsFactory +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.RequiresDevice import androidx.test.platform.app.InstrumentationRegistry import com.android.server.wm.flicker.helpers.SimpleAppHelper diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt index 3aee93296eee..b1d78cbc034e 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt @@ -20,20 +20,20 @@ import android.app.Instrumentation import android.app.WallpaperManager import android.content.res.Resources import android.platform.test.annotations.Presubmit -import android.tools.common.datatypes.Region -import android.tools.common.flicker.subject.layers.LayersTraceSubject -import android.tools.common.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.common.traces.component.ComponentNameMatcher.Companion.SPLASH_SCREEN -import android.tools.common.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER -import android.tools.common.traces.component.ComponentSplashScreenMatcher -import android.tools.common.traces.component.IComponentMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.WindowUtils -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.datatypes.Region +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.subject.layers.LayersTraceSubject +import android.tools.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS +import android.tools.helpers.WindowUtils +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.component.ComponentNameMatcher.Companion.SPLASH_SCREEN +import android.tools.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER +import android.tools.traces.component.ComponentSplashScreenMatcher +import android.tools.traces.component.IComponentMatcher +import android.tools.traces.parsers.toFlickerComponent import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.BaseTest @@ -215,9 +215,10 @@ class TaskTransitionTest(flicker: LegacyFlickerTest) : BaseTest(flicker) { component: IComponentMatcher, expectedArea: Region, isOptional: Boolean = true - ): LayersTraceSubject = invoke("$component coversExactly $expectedArea", isOptional) { - it.visibleRegion(component).coversExactly(expectedArea) - } + ): LayersTraceSubject = + invoke("$component coversExactly $expectedArea", isOptional) { + it.visibleRegion(component).coversExactly(expectedArea) + } @Parameterized.Parameters(name = "{0}") @JvmStatic diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt index 802c755116af..8a3304b0343d 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt @@ -16,10 +16,10 @@ package com.android.server.wm.flicker.launch.common -import android.tools.common.Rotation -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule +import android.tools.Rotation +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.rules.RemoveAllTasksButHomeRule abstract class OpenAppFromIconTransition(flicker: LegacyFlickerTest) : OpenAppFromLauncherTransition(flicker) { diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt index 9d7096ea0e73..b56e9a51187c 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt @@ -17,8 +17,8 @@ package com.android.server.wm.flicker.launch.common import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.replacesLayer import org.junit.Test diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt index 7b088431b0bb..f8fd35860f6f 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.launch.common import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.navBarLayerPositionAtEnd import com.android.server.wm.flicker.statusBarLayerPositionAtEnd diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt index 989619e08d98..7ca336daaa11 100644 --- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt +++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt @@ -17,11 +17,11 @@ package com.android.server.wm.flicker.launch.common import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.helpers.wakeUpAndGoToHomeScreen +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.helpers.wakeUpAndGoToHomeScreen +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.helpers.setRotation diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt index 8242e9a31992..8a241de32a2b 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt @@ -20,12 +20,12 @@ import android.app.Instrumentation import android.platform.test.rule.NavigationModeRule import android.platform.test.rule.PressHomeRule import android.platform.test.rule.UnlockScreenRule -import android.tools.common.NavBar -import android.tools.common.Rotation +import android.tools.NavBar +import android.tools.Rotation import android.tools.device.apphelpers.MessagingAppHelper -import android.tools.device.flicker.rules.ChangeDisplayOrientationRule -import android.tools.device.flicker.rules.LaunchAppRule -import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.flicker.rules.LaunchAppRule +import android.tools.flicker.rules.RemoveAllTasksButHomeRule import androidx.test.platform.app.InstrumentationRegistry import org.junit.rules.RuleChain diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt index b3c9c96c614c..8040610c485b 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.close.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt index 29c11a4257f6..aacccf4e680c 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.close.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt index 1bb4a253ff41..74ee46093f6e 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.close.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt index 17cb6e194ec3..57463c33c1fa 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.close.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt index 47c25294f66e..3d5f0f2806d6 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt @@ -16,13 +16,13 @@ package com.android.server.wm.flicker.service.close.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.close.scenarios.CloseAppHomeButton import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt index b18148f97759..055cc727dc0b 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt @@ -16,13 +16,13 @@ package com.android.server.wm.flicker.service.close.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.close.scenarios.CloseAppHomeButton import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt index 85430154e202..38779811201d 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.server.wm.flicker.service.close.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.close.scenarios.CloseAppSwipeToHome import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt index f88963b7a341..ef7755e29ccf 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.server.wm.flicker.service.close.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.close.scenarios.CloseAppSwipeToHome import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt index 2aaacde52547..17de26815079 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.service.close.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.tapl.LauncherInstrumentation import com.android.server.wm.flicker.helpers.SimpleAppHelper diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt index 08683a3ab43d..d8a88d4e6fb1 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.service.close.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.tapl.LauncherInstrumentation import com.android.server.wm.flicker.helpers.SimpleAppHelper diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt index 360e11408c92..f32f5ba57a7b 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.service.close.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.tapl.LauncherInstrumentation import com.android.server.wm.flicker.helpers.SimpleAppHelper diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt index bb18770a8e7c..8b087509e486 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt index 1c3cc2188c7c..cc7fe4d1111e 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt index 46d36dbd6b09..f6414ca0ee29 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt index f6a668feeed6..4244900302dc 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt index 93200ba1b6fe..548acbe08945 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt index f5d41d250b1e..b231dd3319bb 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt index 28f322bee130..14f680a05b91 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt index beb3fae8be48..6e07174d49cc 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt index 4adcc8bf5f0b..de71b9aab9c6 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp import org.junit.Ignore import org.junit.Test diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt index f7211e7287cf..714d5e8a7ee0 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp import org.junit.Ignore import org.junit.Test diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt index 1ade9560d90f..4c1bae78a8ad 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp import org.junit.Ignore import org.junit.Test diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt index ea26f0867c7f..0321f779f383 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp import org.junit.Ignore import org.junit.Test diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt index 866190f78827..e3b434d0ae7a 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt index a8d628328ed9..64bce2e4b4df 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt index ef84c3f1177e..83241bf19a33 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt index 5bb6b3713e9f..06b89d38c2c6 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt index 39f25e97f04c..8d3cf9084368 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt index 28816bcba2a1..0d0adf26d57f 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt index 94ffe4e57994..1fbaddbfbb80 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt index e5f5ec4a6fe8..52df4bd809a1 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt @@ -16,14 +16,14 @@ package com.android.server.wm.flicker.service.notification.flicker -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt index ac4e16969bad..79d6bb71cbba 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt @@ -17,7 +17,7 @@ package com.android.server.wm.flicker.service.notification.scenarios import android.app.Instrumentation -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.WindowManagerStateHelper import android.view.WindowInsets import android.view.WindowManager import androidx.test.platform.app.InstrumentationRegistry diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt index 9c53ab30e8cd..e702f12c7538 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.service.notification.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.helpers.wakeUpAndGoToHomeScreen -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.helpers.wakeUpAndGoToHomeScreen +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt index 31f55d9d2e99..0a509f860f76 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.service.notification.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.helpers.wakeUpAndGoToHomeScreen -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.helpers.wakeUpAndGoToHomeScreen +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt index b971555f2747..ce6ee2f05526 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.service.notification.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.helpers.wakeUpAndGoToHomeScreen -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.helpers.wakeUpAndGoToHomeScreen +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt index fed077ed0e50..e1cf32232734 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.service.notification.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.helpers.wakeUpAndGoToHomeScreen -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.helpers.wakeUpAndGoToHomeScreen +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt index 403790e904d8..4dd84bd510c1 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.service.notification.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.helpers.wakeUpAndGoToHomeScreen -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.helpers.wakeUpAndGoToHomeScreen +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt index d611a420edcb..da9f4bb88c1e 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.server.wm.flicker.service.quickswitch.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsBack import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt index e6bcbba661f3..f3ae920e1f87 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.server.wm.flicker.service.quickswitch.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsBack import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt index 2a26d633adaf..a26906cc4a6f 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.server.wm.flicker.service.quickswitch.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsForward import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt index 5ce714371db0..01def0e1cd71 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.server.wm.flicker.service.quickswitch.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsForward import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt index cff47bb8cc19..3f40e56ee0ff 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt @@ -16,13 +16,13 @@ package com.android.server.wm.flicker.service.quickswitch.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchFromLauncher import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt index 33095a6ac078..70a95feef119 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt @@ -16,13 +16,13 @@ package com.android.server.wm.flicker.service.quickswitch.flicker -import android.tools.common.Rotation -import android.tools.common.flicker.FlickerConfig -import android.tools.common.flicker.annotation.ExpectedScenarios -import android.tools.common.flicker.annotation.FlickerConfigProvider -import android.tools.common.flicker.config.FlickerConfig -import android.tools.common.flicker.config.FlickerServiceConfig -import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner +import android.tools.Rotation +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchFromLauncher import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt index a1708fe3a4b6..f0df37a9f37b 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.service.quickswitch.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.flicker.rules.ChangeDisplayOrientationRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.tapl.LauncherInstrumentation import com.android.server.wm.flicker.helpers.NonResizeableAppHelper diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt index fcf442a4e300..a22bdced6fcd 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.service.quickswitch.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.flicker.rules.ChangeDisplayOrientationRule -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.tapl.LauncherInstrumentation import com.android.server.wm.flicker.helpers.NonResizeableAppHelper diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt index 7afe5268ede4..e5aa181c95cd 100644 --- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt +++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.service.quickswitch.scenarios import android.app.Instrumentation -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.NavBar +import android.tools.Rotation +import android.tools.traces.parsers.WindowManagerStateHelper import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.tapl.LauncherInstrumentation import com.android.server.wm.flicker.helpers.SimpleAppHelper diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt index 99e8ef5e4c3d..7e486abbd30f 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt @@ -17,13 +17,13 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.flicker.subject.region.RegionSubject -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.subject.region.RegionSubject +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeEditorPopupDialogAppHelper import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt index 48c54eabc5e2..2f3ec6301215 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt @@ -18,12 +18,12 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeAppHelper import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt index 31d5d7f837d5..8821b69cdb3e 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt @@ -17,12 +17,12 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt index 180ae5d6f097..d75eba68c7cc 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt @@ -17,12 +17,12 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt index a0573b7b4b16..41d9e30a17ee 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt @@ -18,11 +18,11 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeAppHelper import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt index be47ec7098f9..0e7fb7975df8 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt @@ -18,13 +18,13 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS +import android.tools.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeAppHelper import com.android.server.wm.flicker.helpers.SimpleAppHelper diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt index 994edc592f5d..47a7e1b65b2d 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt @@ -16,15 +16,15 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.flicker.subject.region.RegionSubject -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.WindowUtils +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.subject.region.RegionSubject +import android.tools.helpers.WindowUtils +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt index ea7c7c4276dc..e8249bca4c2d 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt @@ -18,13 +18,13 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.subject.layers.LayerTraceEntrySubject +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt index b7a183d7f7fe..617237d37368 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt @@ -17,12 +17,12 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper import com.android.server.wm.flicker.helpers.setRotation diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt index 6ee5a9a775b3..7b62c8967628 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt @@ -17,13 +17,13 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper import com.android.server.wm.flicker.helpers.SimpleAppHelper diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt index 1ad5c0de282b..53bfb4ecf66f 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt @@ -17,12 +17,12 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper import com.android.server.wm.flicker.helpers.ImeStateInitializeHelper diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt index 918e1ea3bcd0..12290af8fd46 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt @@ -18,11 +18,11 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeAppHelper import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt index 181a2a229940..0948351ac65b 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt @@ -17,13 +17,13 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.Rotation +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.toFlickerComponent import android.view.WindowInsets.Type.ime import android.view.WindowInsets.Type.navigationBars import android.view.WindowInsets.Type.statusBars @@ -55,10 +55,12 @@ class ShowImeWhileDismissingThemedPopupDialogTest(flicker: LegacyFlickerTest) : testApp.launchViaIntent(wmHelper) testApp.waitIMEShown(wmHelper) broadcastActionTrigger.doAction(ACTION_START_DIALOG_THEMED_ACTIVITY) - wmHelper.StateSyncBuilder() - .withFullScreenApp( - ActivityOptions.DialogThemedActivity.COMPONENT.toFlickerComponent()) - .waitForAndVerify() + wmHelper + .StateSyncBuilder() + .withFullScreenApp( + ActivityOptions.DialogThemedActivity.COMPONENT.toFlickerComponent() + ) + .waitForAndVerify() // Verify IME insets isn't visible on dialog since it's non-IME focusable window assertFalse(testApp.getInsetsVisibleFromDialog(ime())) assertTrue(testApp.getInsetsVisibleFromDialog(statusBars())) diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt index f1bc125b99dc..a14dc62b0023 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt @@ -17,13 +17,13 @@ package com.android.server.wm.flicker.ime import android.platform.test.annotations.Presubmit -import android.tools.common.traces.ConditionsFactory -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.traces.parsers.WindowManagerStateHelper +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.ConditionsFactory +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.WindowManagerStateHelper import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt index 777231e001f7..bd3d1ce3de50 100644 --- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt +++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt @@ -18,8 +18,8 @@ package com.android.server.wm.flicker.ime -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher fun LegacyFlickerTest.imeLayerBecomesVisible() { assertLayers { diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt index b81439e8a1d1..edcee46affe6 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt @@ -16,7 +16,7 @@ package com.android.server.wm.flicker.notification -import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.traces.component.ComponentNameMatcher object Consts { val IMAGE_WALLPAPER = ComponentNameMatcher("", "com.android.systemui.wallpapers.ImageWallpaper") diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt index 620502e521c4..ffaeeadb1042 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt @@ -20,12 +20,12 @@ import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit import android.platform.test.rule.SettingOverrideRule import android.provider.Settings -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.wakeUpAndGoToHomeScreen +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.wakeUpAndGoToHomeScreen +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.RequiresDevice import org.junit.ClassRule import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt index 2a458ef82448..6e67e193ed8c 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt @@ -19,11 +19,11 @@ package com.android.server.wm.flicker.notification import android.platform.test.annotations.Presubmit import android.platform.test.rule.SettingOverrideRule import android.provider.Settings -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.statusBarLayerPositionAtEnd diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt index 00aad2783d5d..8e210d455591 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt @@ -18,12 +18,12 @@ package com.android.server.wm.flicker.notification import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.wakeUpAndGoToHomeScreen +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.wakeUpAndGoToHomeScreen +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.FlakyTest import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.ShowWhenLockedAppHelper diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt index f8d78b5ddd1e..b6d09d0bf3bb 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt @@ -18,12 +18,12 @@ package com.android.server.wm.flicker.notification import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.wakeUpAndGoToHomeScreen +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.wakeUpAndGoToHomeScreen +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.statusBarLayerPositionAtEnd import org.junit.FixMethodOrder diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt index 5c7ec46d6f04..1e607bfb2f49 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt @@ -18,13 +18,13 @@ package com.android.server.wm.flicker.notification import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.FlickerTestData -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory -import android.tools.device.helpers.wakeUpAndGoToHomeScreen +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.FlickerTestData +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.helpers.wakeUpAndGoToHomeScreen +import android.tools.traces.component.ComponentNameMatcher import android.view.WindowInsets import android.view.WindowManager import androidx.test.uiautomator.By diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt index 4e0e3c04ae5a..4ba444b0815a 100644 --- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt +++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.notification import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.SimpleAppHelper import org.junit.Test diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt index 13fcc2ba0b54..8b09b590e790 100644 --- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt +++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt @@ -17,13 +17,13 @@ package com.android.server.wm.flicker.quickswitch import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.common.datatypes.Rect -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.datatypes.Rect +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.NonResizeableAppHelper diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt index badd7c8c712c..c54ddcf793f6 100644 --- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt +++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt @@ -16,13 +16,13 @@ package com.android.server.wm.flicker.quickswitch -import android.tools.common.NavBar -import android.tools.common.datatypes.Rect -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.datatypes.Rect +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.NonResizeableAppHelper diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt index f51be908750a..69a84a0cbcb0 100644 --- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt +++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt @@ -17,14 +17,14 @@ package com.android.server.wm.flicker.quickswitch import android.platform.test.annotations.Presubmit -import android.tools.common.NavBar -import android.tools.common.Rotation -import android.tools.common.datatypes.Rect -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.NavBar +import android.tools.Rotation +import android.tools.datatypes.Rect +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import androidx.test.filters.FlakyTest import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.SimpleAppHelper diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt index bdbf0d24e624..05ab364ed72c 100644 --- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt +++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt @@ -18,11 +18,11 @@ package com.android.server.wm.flicker.rotation import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.helpers.SimpleAppHelper import org.junit.FixMethodOrder import org.junit.Test diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt index 79d3a10a34cb..c7da778b752b 100644 --- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt +++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt @@ -17,13 +17,13 @@ package com.android.server.wm.flicker.rotation import android.platform.test.annotations.Presubmit -import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.common.traces.component.IComponentMatcher -import android.tools.common.traces.surfaceflinger.Display import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.subject.layers.LayerTraceEntrySubject +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.component.IComponentMatcher +import android.tools.traces.surfaceflinger.Display import com.android.server.wm.flicker.BaseTest import com.android.server.wm.flicker.helpers.setRotation import org.junit.Test @@ -76,9 +76,9 @@ abstract class RotationTransition(flicker: LegacyFlickerTest) : BaseTest(flicker } private fun LayerTraceEntrySubject.getDisplay(componentMatcher: IComponentMatcher): Display { - val stackId = this.layer { - componentMatcher.layerMatchesAnyOf(it) && it.isVisible - }?.layer?.stackId ?: -1 + val stackId = + this.layer { componentMatcher.layerMatchesAnyOf(it) && it.isVisible }?.layer?.stackId + ?: -1 return this.entry.displays.firstOrNull { it.layerStackId == stackId } ?: error("Unable to find visible layer for $componentMatcher") diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt index 6d3ae43c1472..a41362857420 100644 --- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt +++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt @@ -18,13 +18,13 @@ package com.android.server.wm.flicker.rotation import android.platform.test.annotations.PlatinumTest import android.platform.test.annotations.Presubmit -import android.tools.common.ScenarioBuilder -import android.tools.common.ScenarioImpl -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerParametersRunnerFactory -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.flicker.legacy.LegacyFlickerTestFactory +import android.tools.ScenarioBuilder +import android.tools.ScenarioImpl +import android.tools.flicker.junit.FlickerParametersRunnerFactory +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.legacy.LegacyFlickerTestFactory +import android.tools.traces.component.ComponentNameMatcher import android.view.WindowManager import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt index ce92eac3fc59..17f91ebad771 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt @@ -19,10 +19,10 @@ package com.android.server.wm.flicker import android.app.Instrumentation import android.content.Intent import android.platform.test.annotations.Presubmit -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.flicker.junit.FlickerBuilderProvider -import android.tools.device.flicker.legacy.FlickerBuilder -import android.tools.device.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.junit.FlickerBuilderProvider +import android.tools.flicker.legacy.FlickerBuilder +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.traces.component.ComponentNameMatcher import android.util.Log import androidx.test.platform.app.InstrumentationRegistry import com.android.launcher3.tapl.LauncherInstrumentation diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt index 1abb8c217603..8853c1db856f 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt @@ -18,15 +18,15 @@ package com.android.server.wm.flicker -import android.tools.common.PlatformConsts -import android.tools.common.Position -import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject -import android.tools.common.flicker.subject.region.RegionSubject -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.common.traces.component.IComponentNameMatcher -import android.tools.common.traces.wm.WindowManagerTrace -import android.tools.device.flicker.legacy.LegacyFlickerTest -import android.tools.device.helpers.WindowUtils +import android.tools.PlatformConsts +import android.tools.Position +import android.tools.flicker.legacy.LegacyFlickerTest +import android.tools.flicker.subject.layers.LayerTraceEntrySubject +import android.tools.flicker.subject.region.RegionSubject +import android.tools.helpers.WindowUtils +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.component.IComponentNameMatcher +import android.tools.traces.wm.WindowManagerTrace /** * Checks that [ComponentNameMatcher.STATUS_BAR] window is visible and above the app windows in all diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt index 11e6bbe4eb13..4a675be65549 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt @@ -17,12 +17,12 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.PlatformConsts -import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.PlatformConsts import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.helpers.FIND_TIMEOUT -import android.tools.device.traces.parsers.WindowManagerStateHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.helpers.FIND_TIMEOUT +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.toFlickerComponent import android.util.Log import androidx.test.uiautomator.By import androidx.test.uiautomator.Until diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt index 94ac1a6e1e02..ec661d75eb17 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt @@ -17,8 +17,8 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper +import android.tools.traces.component.ComponentNameMatcher class AppPairsHelper( instrumentation: Instrumentation, diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt index fde098199042..53337251640e 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt @@ -19,7 +19,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation import android.content.ComponentName import android.provider.Settings -import android.tools.device.helpers.FIND_TIMEOUT +import android.tools.helpers.FIND_TIMEOUT import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt index c6fa1bb89220..1915225f05b0 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions class FixedOrientationAppHelper diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt index 5c8cbe49d7cf..926209f93128 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt @@ -18,9 +18,9 @@ package com.android.server.wm.flicker.helpers -import android.tools.common.Rotation -import android.tools.device.flicker.legacy.FlickerTestData -import android.tools.device.flicker.rules.ChangeDisplayOrientationRule +import android.tools.Rotation +import android.tools.flicker.legacy.FlickerTestData +import android.tools.flicker.rules.ChangeDisplayOrientationRule /** * Changes the device [rotation] and wait for the rotation animation to complete diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt index 3146139757c1..0c60f284a35b 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.traces.parsers.WindowManagerStateHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.toFlickerComponent import androidx.test.uiautomator.By import androidx.test.uiautomator.Direction import androidx.test.uiautomator.Until diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt index cb1aab0bfeea..495fbce6558a 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt @@ -17,11 +17,11 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.helpers.FIND_TIMEOUT -import android.tools.device.traces.parsers.WindowManagerStateHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.helpers.FIND_TIMEOUT +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.toFlickerComponent import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt index 7a8d780c3d9f..6fe7c29b543d 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.device.helpers.FIND_TIMEOUT -import android.tools.device.traces.parsers.WindowManagerStateHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.helpers.FIND_TIMEOUT +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.toFlickerComponent import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt index 0ee7aeeb30c6..f5c88e3fea5c 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt @@ -17,13 +17,13 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.Rotation -import android.tools.common.traces.component.ComponentNameMatcher -import android.tools.common.traces.component.IComponentMatcher -import android.tools.device.helpers.FIND_TIMEOUT -import android.tools.device.helpers.IME_PACKAGE -import android.tools.device.traces.parsers.WindowManagerStateHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.Rotation +import android.tools.helpers.FIND_TIMEOUT +import android.tools.helpers.IME_PACKAGE +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.component.IComponentMatcher +import android.tools.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.toFlickerComponent import android.view.WindowInsets.Type.ime import android.view.WindowInsets.Type.navigationBars import android.view.WindowInsets.Type.statusBars diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt index b2aeb14aaf78..db93bf7966de 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions class ImeStateInitializeHelper diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt index b95d86b72f34..d6ead85e9666 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt @@ -18,7 +18,7 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions class LaunchBubbleHelper(instrumentation: Instrumentation) : diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt index 9b539c8641d4..b09e53b6400d 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt @@ -17,14 +17,14 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.datatypes.Rect -import android.tools.common.datatypes.Region -import android.tools.common.traces.component.ComponentNameMatcher +import android.tools.datatypes.Rect +import android.tools.datatypes.Region import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.helpers.FIND_TIMEOUT -import android.tools.device.helpers.SYSTEMUI_PACKAGE -import android.tools.device.traces.parsers.WindowManagerStateHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.helpers.FIND_TIMEOUT +import android.tools.helpers.SYSTEMUI_PACKAGE +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.toFlickerComponent import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt index 9895bda7f590..d4075e92d4bc 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt @@ -17,10 +17,10 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.helpers.FIND_TIMEOUT -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.helpers.FIND_TIMEOUT +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.toFlickerComponent import androidx.test.uiautomator.By import androidx.test.uiautomator.Direction import androidx.test.uiautomator.UiObject2 diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt index 65175ef33afb..29c1cde74fac 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt @@ -19,8 +19,8 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation import android.content.Context import android.provider.Settings -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper +import android.tools.traces.component.ComponentNameMatcher import android.util.Log import com.android.compatibility.common.util.SystemUtil import java.io.IOException diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt index b2f8d4748c07..ea4ea0a417df 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt @@ -17,11 +17,11 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.helpers.FIND_TIMEOUT -import android.tools.device.traces.parsers.WindowManagerStateHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.helpers.FIND_TIMEOUT +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.toFlickerComponent import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt index ee65004e9e78..ebf348703f76 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions class NonResizeableAppHelper diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt index e60c20df9967..c559d0faf42d 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt @@ -17,11 +17,11 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.helpers.FIND_TIMEOUT -import android.tools.device.traces.parsers.WindowManagerStateHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.helpers.FIND_TIMEOUT +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.toFlickerComponent import androidx.test.uiautomator.By import androidx.test.uiautomator.Until import com.android.server.wm.flicker.testapp.ActivityOptions diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt index 452c98c65a7f..db933b30a822 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt @@ -20,15 +20,15 @@ import android.app.Instrumentation import android.content.Intent import android.media.session.MediaController import android.media.session.MediaSessionManager -import android.tools.common.datatypes.Rect -import android.tools.common.datatypes.Region -import android.tools.common.traces.ConditionsFactory -import android.tools.common.traces.component.IComponentMatcher +import android.tools.datatypes.Rect +import android.tools.datatypes.Region import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.helpers.FIND_TIMEOUT -import android.tools.device.helpers.SYSTEMUI_PACKAGE -import android.tools.device.traces.parsers.WindowManagerStateHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.helpers.FIND_TIMEOUT +import android.tools.helpers.SYSTEMUI_PACKAGE +import android.tools.traces.ConditionsFactory +import android.tools.traces.component.IComponentMatcher +import android.tools.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.toFlickerComponent import android.util.Log import androidx.test.uiautomator.By import androidx.test.uiautomator.Until diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt index cac3530399de..55d43e654e7e 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions class SeamlessRotationAppHelper diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt index 8366a7a1fe41..05856ccc93c3 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions class ShowWhenLockedAppHelper diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt index 89c6c35af47d..82ef39834e74 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions class SimpleAppHelper diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt index 6311678f1a04..ffe077ecd486 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt @@ -17,9 +17,9 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.toFlickerComponent import com.android.server.wm.flicker.testapp.ActivityOptions class TransferSplashscreenAppHelper diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt index 8be5769f47cf..867bcb6db988 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt @@ -17,11 +17,11 @@ package com.android.server.wm.flicker.helpers import android.app.Instrumentation -import android.tools.common.traces.component.ComponentNameMatcher import android.tools.device.apphelpers.StandardAppHelper -import android.tools.device.helpers.FIND_TIMEOUT -import android.tools.device.traces.parsers.WindowManagerStateHelper -import android.tools.device.traces.parsers.toFlickerComponent +import android.tools.helpers.FIND_TIMEOUT +import android.tools.traces.component.ComponentNameMatcher +import android.tools.traces.parsers.WindowManagerStateHelper +import android.tools.traces.parsers.toFlickerComponent import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.Until diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp index a4877999ff6f..827ff4fbd989 100644 --- a/tests/Internal/Android.bp +++ b/tests/Internal/Android.bp @@ -21,6 +21,9 @@ android_test { "mockito-target-minus-junit4", "truth", "platform-test-annotations", + "flickerlib-parsers", + "perfetto_trace_java_protos", + "flickerlib-trace_processor_shell", ], java_resource_dirs: ["res"], certificate: "platform", diff --git a/tests/Internal/AndroidManifest.xml b/tests/Internal/AndroidManifest.xml index dbba24531769..9a3fe617e70a 100644 --- a/tests/Internal/AndroidManifest.xml +++ b/tests/Internal/AndroidManifest.xml @@ -19,7 +19,11 @@ package="com.android.internal.tests"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.BIND_WALLPAPER"/> - <application> + <!-- Allow the test to connect to perfetto trace processor --> + <uses-permission android:name="android.permission.INTERNET"/> + <application + android:requestLegacyExternalStorage="true" + android:networkSecurityConfig="@xml/network_security_config"> <uses-library android:name="android.test.runner"/> <service android:name="stub.DummyWallpaperService" diff --git a/tests/Internal/res/xml/network_security_config.xml b/tests/Internal/res/xml/network_security_config.xml new file mode 100644 index 000000000000..fdf1dbbe7672 --- /dev/null +++ b/tests/Internal/res/xml/network_security_config.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<network-security-config> + <domain-config cleartextTrafficPermitted="true"> + <domain includeSubdomains="true">localhost</domain> + </domain-config> +</network-security-config> diff --git a/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java new file mode 100644 index 000000000000..a64996c6838e --- /dev/null +++ b/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2019 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.internal.protolog; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static com.android.internal.protolog.LegacyProtoLogImpl.PROTOLOG_VERSION; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +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.content.Context; +import android.os.SystemClock; +import android.platform.test.annotations.Presubmit; +import android.util.proto.ProtoInputStream; + +import androidx.test.filters.SmallTest; + +import com.android.internal.protolog.common.IProtoLogGroup; +import com.android.internal.protolog.common.LogLevel; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.util.LinkedList; + +/** + * Test class for {@link ProtoLogImpl}. + */ +@SuppressWarnings("ConstantConditions") +@SmallTest +@Presubmit +@RunWith(JUnit4.class) +public class LegacyProtoLogImplTest { + + private static final byte[] MAGIC_HEADER = new byte[]{ + 0x9, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47 + }; + + private LegacyProtoLogImpl mProtoLog; + private File mFile; + + @Mock + private LegacyProtoLogViewerConfigReader mReader; + + private final String mViewerConfigFilename = "unused/file/path"; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + final Context testContext = getInstrumentation().getContext(); + mFile = testContext.getFileStreamPath("tracing_test.dat"); + //noinspection ResultOfMethodCallIgnored + mFile.delete(); + mProtoLog = new LegacyProtoLogImpl(mFile, mViewerConfigFilename, + 1024 * 1024, mReader, 1024); + } + + @After + public void tearDown() { + if (mFile != null) { + //noinspection ResultOfMethodCallIgnored + mFile.delete(); + } + ProtoLogImpl.setSingleInstance(null); + } + + @Test + public void isEnabled_returnsFalseByDefault() { + assertFalse(mProtoLog.isProtoEnabled()); + } + + @Test + public void isEnabled_returnsTrueAfterStart() { + mProtoLog.startProtoLog(mock(PrintWriter.class)); + assertTrue(mProtoLog.isProtoEnabled()); + } + + @Test + public void isEnabled_returnsFalseAfterStop() { + mProtoLog.startProtoLog(mock(PrintWriter.class)); + mProtoLog.stopProtoLog(mock(PrintWriter.class), true); + assertFalse(mProtoLog.isProtoEnabled()); + } + + @Test + public void logFile_startsWithMagicHeader() throws Exception { + mProtoLog.startProtoLog(mock(PrintWriter.class)); + mProtoLog.stopProtoLog(mock(PrintWriter.class), true); + + assertTrue("Log file should exist", mFile.exists()); + + byte[] header = new byte[MAGIC_HEADER.length]; + try (InputStream is = new FileInputStream(mFile)) { + assertEquals(MAGIC_HEADER.length, is.read(header)); + assertArrayEquals(MAGIC_HEADER, header); + } + } + + @Test + public void log_logcatEnabledExternalMessage() { + when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% 0x%x %s %f"); + LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog); + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); + TestProtoLogGroup.TEST_GROUP.setLogToProto(false); + + implSpy.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null, + new Object[]{true, 10000, 30000, "test", 0.000003}); + + verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( + LogLevel.INFO), + eq("test true 10000 % 0x7530 test 3.0E-6")); + verify(mReader).getViewerString(eq(1234L)); + } + + @Test + public void log_logcatEnabledInvalidMessage() { + when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% %x %s %f"); + LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog); + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); + TestProtoLogGroup.TEST_GROUP.setLogToProto(false); + + implSpy.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null, + new Object[]{true, 10000, 0.0001, 0.00002, "test"}); + + verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( + LogLevel.INFO), + eq("UNKNOWN MESSAGE (1234) true 10000 1.0E-4 2.0E-5 test")); + verify(mReader).getViewerString(eq(1234L)); + } + + @Test + public void log_logcatEnabledInlineMessage() { + when(mReader.getViewerString(anyLong())).thenReturn("test %d"); + LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog); + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); + TestProtoLogGroup.TEST_GROUP.setLogToProto(false); + + implSpy.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d", + new Object[]{5}); + + verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( + LogLevel.INFO), eq("test 5")); + verify(mReader, never()).getViewerString(anyLong()); + } + + @Test + public void log_logcatEnabledNoMessage() { + when(mReader.getViewerString(anyLong())).thenReturn(null); + LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog); + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); + TestProtoLogGroup.TEST_GROUP.setLogToProto(false); + + implSpy.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null, + new Object[]{5}); + + verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( + LogLevel.INFO), eq("UNKNOWN MESSAGE (1234) 5")); + verify(mReader).getViewerString(eq(1234L)); + } + + @Test + public void log_logcatDisabled() { + when(mReader.getViewerString(anyLong())).thenReturn("test %d"); + LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog); + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false); + TestProtoLogGroup.TEST_GROUP.setLogToProto(false); + + implSpy.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d", + new Object[]{5}); + + verify(implSpy, never()).passToLogcat(any(), any(), any()); + verify(mReader, never()).getViewerString(anyLong()); + } + + private static class ProtoLogData { + Long mMessageHash = null; + Long mElapsedTime = null; + LinkedList<String> mStrParams = new LinkedList<>(); + LinkedList<Long> mSint64Params = new LinkedList<>(); + LinkedList<Double> mDoubleParams = new LinkedList<>(); + LinkedList<Boolean> mBooleanParams = new LinkedList<>(); + } + + private ProtoLogData readProtoLogSingle(ProtoInputStream ip) throws IOException { + while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + if (ip.getFieldNumber() == (int) ProtoLogFileProto.VERSION) { + assertEquals(PROTOLOG_VERSION, ip.readString(ProtoLogFileProto.VERSION)); + continue; + } + if (ip.getFieldNumber() != (int) ProtoLogFileProto.LOG) { + continue; + } + long token = ip.start(ProtoLogFileProto.LOG); + ProtoLogData data = new ProtoLogData(); + while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) { + switch (ip.getFieldNumber()) { + case (int) ProtoLogMessage.MESSAGE_HASH: { + data.mMessageHash = ip.readLong(ProtoLogMessage.MESSAGE_HASH); + break; + } + case (int) ProtoLogMessage.ELAPSED_REALTIME_NANOS: { + data.mElapsedTime = ip.readLong(ProtoLogMessage.ELAPSED_REALTIME_NANOS); + break; + } + case (int) ProtoLogMessage.STR_PARAMS: { + data.mStrParams.add(ip.readString(ProtoLogMessage.STR_PARAMS)); + break; + } + case (int) ProtoLogMessage.SINT64_PARAMS: { + data.mSint64Params.add(ip.readLong(ProtoLogMessage.SINT64_PARAMS)); + break; + } + case (int) ProtoLogMessage.DOUBLE_PARAMS: { + data.mDoubleParams.add(ip.readDouble(ProtoLogMessage.DOUBLE_PARAMS)); + break; + } + case (int) ProtoLogMessage.BOOLEAN_PARAMS: { + data.mBooleanParams.add(ip.readBoolean(ProtoLogMessage.BOOLEAN_PARAMS)); + break; + } + } + } + ip.end(token); + return data; + } + return null; + } + + @Test + public void log_protoEnabled() throws Exception { + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false); + TestProtoLogGroup.TEST_GROUP.setLogToProto(true); + mProtoLog.startProtoLog(mock(PrintWriter.class)); + long before = SystemClock.elapsedRealtimeNanos(); + mProtoLog.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, + 0b1110101001010100, null, + new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true}); + long after = SystemClock.elapsedRealtimeNanos(); + mProtoLog.stopProtoLog(mock(PrintWriter.class), true); + try (InputStream is = new FileInputStream(mFile)) { + ProtoInputStream ip = new ProtoInputStream(is); + ProtoLogData data = readProtoLogSingle(ip); + assertNotNull(data); + assertEquals(1234, data.mMessageHash.longValue()); + assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after); + assertArrayEquals(new String[]{"test"}, data.mStrParams.toArray()); + assertArrayEquals(new Long[]{1L, 2L, 3L}, data.mSint64Params.toArray()); + assertArrayEquals(new Double[]{0.4, 0.5, 0.6}, data.mDoubleParams.toArray()); + assertArrayEquals(new Boolean[]{true}, data.mBooleanParams.toArray()); + } + } + + @Test + public void log_invalidParamsMask() throws Exception { + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false); + TestProtoLogGroup.TEST_GROUP.setLogToProto(true); + mProtoLog.startProtoLog(mock(PrintWriter.class)); + long before = SystemClock.elapsedRealtimeNanos(); + mProtoLog.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, + 0b01100100, null, + new Object[]{"test", 1, 0.1, true}); + long after = SystemClock.elapsedRealtimeNanos(); + mProtoLog.stopProtoLog(mock(PrintWriter.class), true); + try (InputStream is = new FileInputStream(mFile)) { + ProtoInputStream ip = new ProtoInputStream(is); + ProtoLogData data = readProtoLogSingle(ip); + assertNotNull(data); + assertEquals(1234, data.mMessageHash.longValue()); + assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after); + assertArrayEquals(new String[]{"test", "(INVALID PARAMS_MASK) true"}, + data.mStrParams.toArray()); + assertArrayEquals(new Long[]{1L}, data.mSint64Params.toArray()); + assertArrayEquals(new Double[]{0.1}, data.mDoubleParams.toArray()); + assertArrayEquals(new Boolean[]{}, data.mBooleanParams.toArray()); + } + } + + @Test + public void log_protoDisabled() throws Exception { + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false); + TestProtoLogGroup.TEST_GROUP.setLogToProto(false); + mProtoLog.startProtoLog(mock(PrintWriter.class)); + mProtoLog.log(LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, + 0b11, null, new Object[]{true}); + mProtoLog.stopProtoLog(mock(PrintWriter.class), true); + try (InputStream is = new FileInputStream(mFile)) { + ProtoInputStream ip = new ProtoInputStream(is); + ProtoLogData data = readProtoLogSingle(ip); + assertNull(data); + } + } + + private enum TestProtoLogGroup implements IProtoLogGroup { + TEST_GROUP(true, true, false, "WindowManagetProtoLogTest"); + + private final boolean mEnabled; + private volatile boolean mLogToProto; + private volatile boolean mLogToLogcat; + private final String mTag; + + /** + * @param enabled set to false to exclude all log statements for this group from + * compilation, + * they will not be available in runtime. + * @param logToProto enable binary logging for the group + * @param logToLogcat enable text logging for the group + * @param tag name of the source of the logged message + */ + TestProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) { + this.mEnabled = enabled; + this.mLogToProto = logToProto; + this.mLogToLogcat = logToLogcat; + this.mTag = tag; + } + + @Override + public boolean isEnabled() { + return mEnabled; + } + + @Override + public boolean isLogToProto() { + return mLogToProto; + } + + @Override + public boolean isLogToLogcat() { + return mLogToLogcat; + } + + @Override + public boolean isLogToAny() { + return mLogToLogcat || mLogToProto; + } + + @Override + public String getTag() { + return mTag; + } + + @Override + public void setLogToProto(boolean logToProto) { + this.mLogToProto = logToProto; + } + + @Override + public void setLogToLogcat(boolean logToLogcat) { + this.mLogToLogcat = logToLogcat; + } + + } +} diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoDataSourceTest.java b/tests/Internal/src/com/android/internal/protolog/PerfettoDataSourceTest.java new file mode 100644 index 000000000000..b9f1738f9bb7 --- /dev/null +++ b/tests/Internal/src/com/android/internal/protolog/PerfettoDataSourceTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.protolog; + +import static org.junit.Assert.assertThrows; +import static org.junit.Assume.assumeTrue; + +import android.tracing.perfetto.CreateTlsStateArgs; +import android.util.proto.ProtoInputStream; + +import com.android.internal.protolog.common.LogLevel; + +import com.google.common.truth.Truth; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import perfetto.protos.DataSourceConfigOuterClass; +import perfetto.protos.ProtologCommon; +import perfetto.protos.ProtologConfig; + +public class PerfettoDataSourceTest { + @Before + public void before() { + assumeTrue(android.tracing.Flags.perfettoProtolog()); + } + + @Test + public void noConfig() { + final ProtoLogDataSource.TlsState tlsState = createTlsState( + DataSourceConfigOuterClass.DataSourceConfig.newBuilder().build()); + + Truth.assertThat(tlsState.getLogFromLevel("SOME_TAG")).isEqualTo(LogLevel.WTF); + Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isFalse(); + } + + @Test + public void defaultTraceMode() { + final ProtoLogDataSource.TlsState tlsState = createTlsState( + DataSourceConfigOuterClass.DataSourceConfig.newBuilder() + .setProtologConfig( + ProtologConfig.ProtoLogConfig.newBuilder() + .setTracingMode( + ProtologConfig.ProtoLogConfig.TracingMode + .ENABLE_ALL) + .build() + ).build()); + + Truth.assertThat(tlsState.getLogFromLevel("SOME_TAG")).isEqualTo(LogLevel.DEBUG); + Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isFalse(); + } + + @Test + public void allEnabledTraceMode() { + final ProtoLogDataSource ds = new ProtoLogDataSource(() -> {}, () -> {}, () -> {}); + + final ProtoLogDataSource.TlsState tlsState = createTlsState( + DataSourceConfigOuterClass.DataSourceConfig.newBuilder().setProtologConfig( + ProtologConfig.ProtoLogConfig.newBuilder() + .setTracingMode( + ProtologConfig.ProtoLogConfig.TracingMode.ENABLE_ALL) + .build() + ).build() + ); + + Truth.assertThat(tlsState.getLogFromLevel("SOME_TAG")).isEqualTo(LogLevel.DEBUG); + Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isFalse(); + } + + @Test + public void requireGroupTagInOverrides() { + Exception exception = assertThrows(RuntimeException.class, () -> { + createTlsState(DataSourceConfigOuterClass.DataSourceConfig.newBuilder() + .setProtologConfig( + ProtologConfig.ProtoLogConfig.newBuilder() + .addGroupOverrides( + ProtologConfig.ProtoLogGroup.newBuilder() + .setLogFrom( + ProtologCommon.ProtoLogLevel + .PROTOLOG_LEVEL_WARN) + .setCollectStacktrace(true) + ) + .build() + ).build()); + }); + + Truth.assertThat(exception).hasMessageThat().contains("group override without a group tag"); + } + + @Test + public void stackTraceCollection() { + final ProtoLogDataSource.TlsState tlsState = createTlsState( + DataSourceConfigOuterClass.DataSourceConfig.newBuilder().setProtologConfig( + ProtologConfig.ProtoLogConfig.newBuilder() + .addGroupOverrides( + ProtologConfig.ProtoLogGroup.newBuilder() + .setGroupName("SOME_TAG") + .setCollectStacktrace(true) + ) + .build() + ).build()); + + Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isTrue(); + } + + @Test + public void groupLogFromOverrides() { + final ProtoLogDataSource.TlsState tlsState = createTlsState( + DataSourceConfigOuterClass.DataSourceConfig.newBuilder().setProtologConfig( + ProtologConfig.ProtoLogConfig.newBuilder() + .addGroupOverrides( + ProtologConfig.ProtoLogGroup.newBuilder() + .setGroupName("SOME_TAG") + .setLogFrom( + ProtologCommon.ProtoLogLevel + .PROTOLOG_LEVEL_DEBUG) + .setCollectStacktrace(true) + ) + .addGroupOverrides( + ProtologConfig.ProtoLogGroup.newBuilder() + .setGroupName("SOME_OTHER_TAG") + .setLogFrom( + ProtologCommon.ProtoLogLevel + .PROTOLOG_LEVEL_WARN) + ) + .build() + ).build()); + + Truth.assertThat(tlsState.getLogFromLevel("SOME_TAG")).isEqualTo(LogLevel.DEBUG); + Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isTrue(); + + Truth.assertThat(tlsState.getLogFromLevel("SOME_OTHER_TAG")).isEqualTo(LogLevel.WARN); + Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_OTHER_TAG")).isFalse(); + + Truth.assertThat(tlsState.getLogFromLevel("UNKNOWN_TAG")).isEqualTo(LogLevel.WTF); + Truth.assertThat(tlsState.getShouldCollectStacktrace("UNKNOWN_TAG")).isFalse(); + } + + private ProtoLogDataSource.TlsState createTlsState( + DataSourceConfigOuterClass.DataSourceConfig config) { + final ProtoLogDataSource ds = + Mockito.spy(new ProtoLogDataSource(() -> {}, () -> {}, () -> {})); + + ProtoInputStream configStream = new ProtoInputStream(config.toByteArray()); + final ProtoLogDataSource.Instance dsInstance = Mockito.spy( + ds.createInstance(configStream, 8)); + Mockito.doNothing().when(dsInstance).release(); + final CreateTlsStateArgs mockCreateTlsStateArgs = Mockito.mock(CreateTlsStateArgs.class); + Mockito.when(mockCreateTlsStateArgs.getDataSourceInstanceLocked()).thenReturn(dsInstance); + return ds.createTlsState(mockCreateTlsStateArgs); + } +} diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java new file mode 100644 index 000000000000..270f5957a9b9 --- /dev/null +++ b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java @@ -0,0 +1,586 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.protolog; + +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import static java.io.File.createTempFile; +import static java.nio.file.Files.createTempDirectory; + +import android.content.Context; +import android.os.SystemClock; +import android.platform.test.annotations.Presubmit; +import android.tools.ScenarioBuilder; +import android.tools.traces.TraceConfig; +import android.tools.traces.TraceConfigs; +import android.tools.traces.io.ResultReader; +import android.tools.traces.io.ResultWriter; +import android.tools.traces.monitors.PerfettoTraceMonitor; +import android.tools.traces.protolog.ProtoLogTrace; +import android.tracing.perfetto.DataSource; +import android.util.proto.ProtoInputStream; + +import androidx.test.filters.SmallTest; + +import com.android.internal.protolog.common.IProtoLogGroup; +import com.android.internal.protolog.common.LogDataType; +import com.android.internal.protolog.common.LogLevel; + +import com.google.common.truth.Truth; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Random; + +import perfetto.protos.Protolog; +import perfetto.protos.ProtologCommon; + +/** + * Test class for {@link ProtoLogImpl}. + */ +@SuppressWarnings("ConstantConditions") +@SmallTest +@Presubmit +@RunWith(JUnit4.class) +public class PerfettoProtoLogImplTest { + private final File mTracingDirectory = createTempDirectory("temp").toFile(); + + private final ResultWriter mWriter = new ResultWriter() + .forScenario(new ScenarioBuilder() + .forClass(createTempFile("temp", "").getName()).build()) + .withOutputDir(mTracingDirectory) + .setRunComplete(); + + private final TraceConfigs mTraceConfig = new TraceConfigs( + new TraceConfig(false, true, false), + new TraceConfig(false, true, false), + new TraceConfig(false, true, false), + new TraceConfig(false, true, false) + ); + + private PerfettoProtoLogImpl mProtoLog; + private Protolog.ProtoLogViewerConfig.Builder mViewerConfigBuilder; + private File mFile; + + private ProtoLogViewerConfigReader mReader; + + public PerfettoProtoLogImplTest() throws IOException { + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + final Context testContext = getInstrumentation().getContext(); + mFile = testContext.getFileStreamPath("tracing_test.dat"); + //noinspection ResultOfMethodCallIgnored + mFile.delete(); + + mViewerConfigBuilder = Protolog.ProtoLogViewerConfig.newBuilder() + .addGroups( + Protolog.ProtoLogViewerConfig.Group.newBuilder() + .setId(1) + .setName(TestProtoLogGroup.TEST_GROUP.toString()) + .setTag(TestProtoLogGroup.TEST_GROUP.getTag()) + ).addMessages( + Protolog.ProtoLogViewerConfig.MessageData.newBuilder() + .setMessageId(1) + .setMessage("My Test Debug Log Message %b") + .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_DEBUG) + .setGroupId(1) + ).addMessages( + Protolog.ProtoLogViewerConfig.MessageData.newBuilder() + .setMessageId(2) + .setMessage("My Test Verbose Log Message %b") + .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_VERBOSE) + .setGroupId(1) + ).addMessages( + Protolog.ProtoLogViewerConfig.MessageData.newBuilder() + .setMessageId(3) + .setMessage("My Test Warn Log Message %b") + .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_WARN) + .setGroupId(1) + ).addMessages( + Protolog.ProtoLogViewerConfig.MessageData.newBuilder() + .setMessageId(4) + .setMessage("My Test Error Log Message %b") + .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_ERROR) + .setGroupId(1) + ).addMessages( + Protolog.ProtoLogViewerConfig.MessageData.newBuilder() + .setMessageId(5) + .setMessage("My Test WTF Log Message %b") + .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_WTF) + .setGroupId(1) + ); + + ViewerConfigInputStreamProvider viewerConfigInputStreamProvider = Mockito.mock( + ViewerConfigInputStreamProvider.class); + Mockito.when(viewerConfigInputStreamProvider.getInputStream()) + .thenAnswer(it -> new ProtoInputStream(mViewerConfigBuilder.build().toByteArray())); + + mReader = Mockito.spy(new ProtoLogViewerConfigReader(viewerConfigInputStreamProvider)); + mProtoLog = new PerfettoProtoLogImpl(viewerConfigInputStreamProvider, mReader); + } + + @After + public void tearDown() { + if (mFile != null) { + //noinspection ResultOfMethodCallIgnored + mFile.delete(); + } + ProtoLogImpl.setSingleInstance(null); + } + + @Test + public void isEnabled_returnsFalseByDefault() { + assertFalse(mProtoLog.isProtoEnabled()); + } + + @Test + public void isEnabled_returnsTrueAfterStart() { + PerfettoTraceMonitor traceMonitor = + PerfettoTraceMonitor.newBuilder().enableProtoLog().build(); + try { + traceMonitor.start(); + assertTrue(mProtoLog.isProtoEnabled()); + } finally { + traceMonitor.stop(mWriter); + } + } + + @Test + public void isEnabled_returnsFalseAfterStop() { + PerfettoTraceMonitor traceMonitor = + PerfettoTraceMonitor.newBuilder().enableProtoLog().build(); + try { + traceMonitor.start(); + assertTrue(mProtoLog.isProtoEnabled()); + } finally { + traceMonitor.stop(mWriter); + } + + assertFalse(mProtoLog.isProtoEnabled()); + } + + @Test + public void defaultMode() throws IOException { + PerfettoTraceMonitor traceMonitor = + PerfettoTraceMonitor.newBuilder().enableProtoLog(false).build(); + try { + traceMonitor.start(); + // Shouldn't be logging anything except WTF unless explicitly requested in the group + // override. + mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5, + LogDataType.BOOLEAN, null, new Object[]{true}); + } finally { + traceMonitor.stop(mWriter); + } + + final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); + final ProtoLogTrace protolog = reader.readProtoLogTrace(); + + Truth.assertThat(protolog.messages).hasSize(1); + Truth.assertThat(protolog.messages.getFirst().getLevel()).isEqualTo(LogLevel.WTF); + } + + @Test + public void respectsOverrideConfigs_defaultMode() throws IOException { + PerfettoTraceMonitor traceMonitor = + PerfettoTraceMonitor.newBuilder().enableProtoLog(true, + List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride( + TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG, true))) + .build(); + try { + traceMonitor.start(); + mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5, + LogDataType.BOOLEAN, null, new Object[]{true}); + } finally { + traceMonitor.stop(mWriter); + } + + final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); + final ProtoLogTrace protolog = reader.readProtoLogTrace(); + + Truth.assertThat(protolog.messages).hasSize(5); + Truth.assertThat(protolog.messages.get(0).getLevel()).isEqualTo(LogLevel.DEBUG); + Truth.assertThat(protolog.messages.get(1).getLevel()).isEqualTo(LogLevel.VERBOSE); + Truth.assertThat(protolog.messages.get(2).getLevel()).isEqualTo(LogLevel.WARN); + Truth.assertThat(protolog.messages.get(3).getLevel()).isEqualTo(LogLevel.ERROR); + Truth.assertThat(protolog.messages.get(4).getLevel()).isEqualTo(LogLevel.WTF); + } + + @Test + public void respectsOverrideConfigs_allEnabledMode() throws IOException { + PerfettoTraceMonitor traceMonitor = + PerfettoTraceMonitor.newBuilder().enableProtoLog(true, + List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride( + TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.WARN, false))) + .build(); + try { + traceMonitor.start(); + mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5, + LogDataType.BOOLEAN, null, new Object[]{true}); + } finally { + traceMonitor.stop(mWriter); + } + + final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); + final ProtoLogTrace protolog = reader.readProtoLogTrace(); + + Truth.assertThat(protolog.messages).hasSize(3); + Truth.assertThat(protolog.messages.get(0).getLevel()).isEqualTo(LogLevel.WARN); + Truth.assertThat(protolog.messages.get(1).getLevel()).isEqualTo(LogLevel.ERROR); + Truth.assertThat(protolog.messages.get(2).getLevel()).isEqualTo(LogLevel.WTF); + } + + @Test + public void respectsAllEnabledMode() throws IOException { + PerfettoTraceMonitor traceMonitor = + PerfettoTraceMonitor.newBuilder().enableProtoLog(true, List.of()) + .build(); + try { + traceMonitor.start(); + mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4, + LogDataType.BOOLEAN, null, new Object[]{true}); + mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5, + LogDataType.BOOLEAN, null, new Object[]{true}); + } finally { + traceMonitor.stop(mWriter); + } + + final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); + final ProtoLogTrace protolog = reader.readProtoLogTrace(); + + Truth.assertThat(protolog.messages).hasSize(5); + Truth.assertThat(protolog.messages.get(0).getLevel()).isEqualTo(LogLevel.DEBUG); + Truth.assertThat(protolog.messages.get(1).getLevel()).isEqualTo(LogLevel.VERBOSE); + Truth.assertThat(protolog.messages.get(2).getLevel()).isEqualTo(LogLevel.WARN); + Truth.assertThat(protolog.messages.get(3).getLevel()).isEqualTo(LogLevel.ERROR); + Truth.assertThat(protolog.messages.get(4).getLevel()).isEqualTo(LogLevel.WTF); + } + + @Test + public void log_logcatEnabledExternalMessage() { + when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% 0x%x %s %f"); + PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog); + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); + TestProtoLogGroup.TEST_GROUP.setLogToProto(false); + + implSpy.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null, + new Object[]{true, 10000, 30000, "test", 0.000003}); + + verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( + LogLevel.INFO), + eq("test true 10000 % 0x7530 test 3.0E-6")); + verify(mReader).getViewerString(eq(1234L)); + } + + @Test + public void log_logcatEnabledInvalidMessage() { + when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% %x %s %f"); + PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog); + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); + TestProtoLogGroup.TEST_GROUP.setLogToProto(false); + + implSpy.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null, + new Object[]{true, 10000, 0.0001, 0.00002, "test"}); + + verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( + LogLevel.INFO), + eq("UNKNOWN MESSAGE (1234) true 10000 1.0E-4 2.0E-5 test")); + verify(mReader).getViewerString(eq(1234L)); + } + + @Test + public void log_logcatEnabledInlineMessage() { + when(mReader.getViewerString(anyLong())).thenReturn("test %d"); + PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog); + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); + TestProtoLogGroup.TEST_GROUP.setLogToProto(false); + + implSpy.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d", + new Object[]{5}); + + verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( + LogLevel.INFO), eq("test 5")); + verify(mReader, never()).getViewerString(anyLong()); + } + + @Test + public void log_logcatEnabledNoMessage() { + when(mReader.getViewerString(anyLong())).thenReturn(null); + PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog); + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); + TestProtoLogGroup.TEST_GROUP.setLogToProto(false); + + implSpy.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null, + new Object[]{5}); + + verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( + LogLevel.INFO), eq("UNKNOWN MESSAGE (1234) 5")); + verify(mReader).getViewerString(eq(1234L)); + } + + @Test + public void log_logcatDisabled() { + when(mReader.getViewerString(anyLong())).thenReturn("test %d"); + PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog); + TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false); + + implSpy.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d", + new Object[]{5}); + + verify(implSpy, never()).passToLogcat(any(), any(), any()); + verify(mReader, never()).getViewerString(anyLong()); + } + + @Test + public void log_protoEnabled() throws Exception { + final long messageHash = addMessageToConfig( + ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_INFO, + "My test message :: %s, %d, %o, %x, %f, %e, %g, %b"); + + PerfettoTraceMonitor traceMonitor = + PerfettoTraceMonitor.newBuilder().enableProtoLog().build(); + long before; + long after; + try { + traceMonitor.start(); + assertTrue(mProtoLog.isProtoEnabled()); + + before = SystemClock.elapsedRealtimeNanos(); + mProtoLog.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, messageHash, + 0b1110101001010100, null, + new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true}); + after = SystemClock.elapsedRealtimeNanos(); + } finally { + traceMonitor.stop(mWriter); + } + + final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); + final ProtoLogTrace protolog = reader.readProtoLogTrace(); + + Truth.assertThat(protolog.messages).hasSize(1); + Truth.assertThat(protolog.messages.getFirst().getTimestamp().getElapsedNanos()) + .isAtLeast(before); + Truth.assertThat(protolog.messages.getFirst().getTimestamp().getElapsedNanos()) + .isAtMost(after); + Truth.assertThat(protolog.messages.getFirst().getMessage()) + .isEqualTo("My test message :: test, 2, 4, 6, 0.400000, 5.000000e-01, 0.6, true"); + } + + private long addMessageToConfig(ProtologCommon.ProtoLogLevel logLevel, String message) { + final long messageId = new Random().nextLong(); + mViewerConfigBuilder.addMessages(Protolog.ProtoLogViewerConfig.MessageData.newBuilder() + .setMessageId(messageId) + .setMessage(message) + .setLevel(logLevel) + .setGroupId(1) + ); + + return messageId; + } + + @Test + public void log_invalidParamsMask() { + final long messageHash = addMessageToConfig( + ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_INFO, + "My test message :: %s, %d, %f, %b"); + PerfettoTraceMonitor traceMonitor = + PerfettoTraceMonitor.newBuilder().enableProtoLog().build(); + long before; + long after; + try { + traceMonitor.start(); + before = SystemClock.elapsedRealtimeNanos(); + mProtoLog.log( + LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, messageHash, + 0b01100100, null, + new Object[]{"test", 1, 0.1, true}); + after = SystemClock.elapsedRealtimeNanos(); + } finally { + traceMonitor.stop(mWriter); + } + + final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); + assertThrows(IllegalStateException.class, reader::readProtoLogTrace); + } + + @Test + public void log_protoDisabled() throws Exception { + PerfettoTraceMonitor traceMonitor = + PerfettoTraceMonitor.newBuilder().enableProtoLog(false).build(); + try { + traceMonitor.start(); + mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1, + 0b11, null, new Object[]{true}); + } finally { + traceMonitor.stop(mWriter); + } + + final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); + final ProtoLogTrace protolog = reader.readProtoLogTrace(); + + Truth.assertThat(protolog.messages).isEmpty(); + } + + @Test + public void stackTraceTrimmed() throws IOException { + PerfettoTraceMonitor traceMonitor = + PerfettoTraceMonitor.newBuilder().enableProtoLog(true, + List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride( + TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG, true))) + .build(); + try { + traceMonitor.start(); + + ProtoLogImpl.setSingleInstance(mProtoLog); + ProtoLogImpl.d(TestProtoLogGroup.TEST_GROUP, 1, + 0b11, null, true); + } finally { + traceMonitor.stop(mWriter); + } + + final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig); + final ProtoLogTrace protolog = reader.readProtoLogTrace(); + + Truth.assertThat(protolog.messages).hasSize(1); + String stacktrace = protolog.messages.getFirst().getStacktrace(); + Truth.assertThat(stacktrace) + .doesNotContain(PerfettoProtoLogImpl.class.getSimpleName() + ".java"); + Truth.assertThat(stacktrace).doesNotContain(DataSource.class.getSimpleName() + ".java"); + Truth.assertThat(stacktrace) + .doesNotContain(ProtoLogImpl.class.getSimpleName() + ".java"); + Truth.assertThat(stacktrace).contains(PerfettoProtoLogImplTest.class.getSimpleName()); + Truth.assertThat(stacktrace).contains("stackTraceTrimmed"); + } + + private enum TestProtoLogGroup implements IProtoLogGroup { + TEST_GROUP(true, true, false, "TEST_TAG"); + + private final boolean mEnabled; + private volatile boolean mLogToProto; + private volatile boolean mLogToLogcat; + private final String mTag; + + /** + * @param enabled set to false to exclude all log statements for this group from + * compilation, + * they will not be available in runtime. + * @param logToProto enable binary logging for the group + * @param logToLogcat enable text logging for the group + * @param tag name of the source of the logged message + */ + TestProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) { + this.mEnabled = enabled; + this.mLogToProto = logToProto; + this.mLogToLogcat = logToLogcat; + this.mTag = tag; + } + + @Override + public boolean isEnabled() { + return mEnabled; + } + + @Override + public boolean isLogToProto() { + return mLogToProto; + } + + @Override + public boolean isLogToLogcat() { + return mLogToLogcat; + } + + @Override + public boolean isLogToAny() { + return mLogToLogcat || mLogToProto; + } + + @Override + public String getTag() { + return mTag; + } + + @Override + public void setLogToProto(boolean logToProto) { + this.mLogToProto = logToProto; + } + + @Override + public void setLogToLogcat(boolean logToLogcat) { + this.mLogToLogcat = logToLogcat; + } + + } +} diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java index 7deb8c73d1fc..4267c2c127ae 100644 --- a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java +++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java @@ -16,49 +16,23 @@ package com.android.internal.protolog; -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; - -import static com.android.internal.protolog.ProtoLogImpl.PROTOLOG_VERSION; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; 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.content.Context; -import android.os.SystemClock; import android.platform.test.annotations.Presubmit; -import android.util.proto.ProtoInputStream; import androidx.test.filters.SmallTest; +import com.android.internal.protolog.common.IProtoLog; import com.android.internal.protolog.common.IProtoLogGroup; +import com.android.internal.protolog.common.LogLevel; import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.util.LinkedList; /** * Test class for {@link ProtoLogImpl}. @@ -68,336 +42,78 @@ import java.util.LinkedList; @Presubmit @RunWith(JUnit4.class) public class ProtoLogImplTest { - - private static final byte[] MAGIC_HEADER = new byte[]{ - 0x9, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47 - }; - - private ProtoLogImpl mProtoLog; - private File mFile; - - @Mock - private ProtoLogViewerConfigReader mReader; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - final Context testContext = getInstrumentation().getContext(); - mFile = testContext.getFileStreamPath("tracing_test.dat"); - //noinspection ResultOfMethodCallIgnored - mFile.delete(); - mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader, 1024); - } - @After public void tearDown() { - if (mFile != null) { - //noinspection ResultOfMethodCallIgnored - mFile.delete(); - } ProtoLogImpl.setSingleInstance(null); } @Test - public void isEnabled_returnsFalseByDefault() { - assertFalse(mProtoLog.isProtoEnabled()); - } - - @Test - public void isEnabled_returnsTrueAfterStart() { - mProtoLog.startProtoLog(mock(PrintWriter.class)); - assertTrue(mProtoLog.isProtoEnabled()); - } - - @Test - public void isEnabled_returnsFalseAfterStop() { - mProtoLog.startProtoLog(mock(PrintWriter.class)); - mProtoLog.stopProtoLog(mock(PrintWriter.class), true); - assertFalse(mProtoLog.isProtoEnabled()); - } - - @Test - public void logFile_startsWithMagicHeader() throws Exception { - mProtoLog.startProtoLog(mock(PrintWriter.class)); - mProtoLog.stopProtoLog(mock(PrintWriter.class), true); - - assertTrue("Log file should exist", mFile.exists()); - - byte[] header = new byte[MAGIC_HEADER.length]; - try (InputStream is = new FileInputStream(mFile)) { - assertEquals(MAGIC_HEADER.length, is.read(header)); - assertArrayEquals(MAGIC_HEADER, header); - } - } - - @Test public void getSingleInstance() { - ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class); + IProtoLog mockedProtoLog = mock(IProtoLog.class); ProtoLogImpl.setSingleInstance(mockedProtoLog); assertSame(mockedProtoLog, ProtoLogImpl.getSingleInstance()); } @Test public void d_logCalled() { - ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class); + IProtoLog mockedProtoLog = mock(IProtoLog.class); ProtoLogImpl.setSingleInstance(mockedProtoLog); ProtoLogImpl.d(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d"); - verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.DEBUG), eq( + verify(mockedProtoLog).log(eq(LogLevel.DEBUG), eq( TestProtoLogGroup.TEST_GROUP), - eq(1234), eq(4321), eq("test %d"), eq(new Object[]{})); + eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{})); } @Test public void v_logCalled() { - ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class); + IProtoLog mockedProtoLog = mock(IProtoLog.class); ProtoLogImpl.setSingleInstance(mockedProtoLog); ProtoLogImpl.v(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d"); - verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.VERBOSE), eq( + verify(mockedProtoLog).log(eq(LogLevel.VERBOSE), eq( TestProtoLogGroup.TEST_GROUP), - eq(1234), eq(4321), eq("test %d"), eq(new Object[]{})); + eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{})); } @Test public void i_logCalled() { - ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class); + IProtoLog mockedProtoLog = mock(IProtoLog.class); ProtoLogImpl.setSingleInstance(mockedProtoLog); ProtoLogImpl.i(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d"); - verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.INFO), eq( + verify(mockedProtoLog).log(eq(LogLevel.INFO), eq( TestProtoLogGroup.TEST_GROUP), - eq(1234), eq(4321), eq("test %d"), eq(new Object[]{})); + eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{})); } @Test public void w_logCalled() { - ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class); + IProtoLog mockedProtoLog = mock(IProtoLog.class); ProtoLogImpl.setSingleInstance(mockedProtoLog); ProtoLogImpl.w(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d"); - verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.WARN), eq( + verify(mockedProtoLog).log(eq(LogLevel.WARN), eq( TestProtoLogGroup.TEST_GROUP), - eq(1234), eq(4321), eq("test %d"), eq(new Object[]{})); + eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{})); } @Test public void e_logCalled() { - ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class); + IProtoLog mockedProtoLog = mock(IProtoLog.class); ProtoLogImpl.setSingleInstance(mockedProtoLog); ProtoLogImpl.e(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d"); - verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.ERROR), eq( + verify(mockedProtoLog).log(eq(LogLevel.ERROR), eq( TestProtoLogGroup.TEST_GROUP), - eq(1234), eq(4321), eq("test %d"), eq(new Object[]{})); + eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{})); } @Test public void wtf_logCalled() { - ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class); + IProtoLog mockedProtoLog = mock(IProtoLog.class); ProtoLogImpl.setSingleInstance(mockedProtoLog); ProtoLogImpl.wtf(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d"); - verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.WTF), eq( + verify(mockedProtoLog).log(eq(LogLevel.WTF), eq( TestProtoLogGroup.TEST_GROUP), - eq(1234), eq(4321), eq("test %d"), eq(new Object[]{})); - } - - @Test - public void log_logcatEnabledExternalMessage() { - when(mReader.getViewerString(anyInt())).thenReturn("test %b %d %% 0x%x %s %f"); - ProtoLogImpl implSpy = Mockito.spy(mProtoLog); - TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); - TestProtoLogGroup.TEST_GROUP.setLogToProto(false); - - implSpy.log( - ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null, - new Object[]{true, 10000, 30000, "test", 0.000003}); - - verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( - ProtoLogImpl.LogLevel.INFO), - eq("test true 10000 % 0x7530 test 3.0E-6")); - verify(mReader).getViewerString(eq(1234)); - } - - @Test - public void log_logcatEnabledInvalidMessage() { - when(mReader.getViewerString(anyInt())).thenReturn("test %b %d %% %x %s %f"); - ProtoLogImpl implSpy = Mockito.spy(mProtoLog); - TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); - TestProtoLogGroup.TEST_GROUP.setLogToProto(false); - - implSpy.log( - ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null, - new Object[]{true, 10000, 0.0001, 0.00002, "test"}); - - verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( - ProtoLogImpl.LogLevel.INFO), - eq("UNKNOWN MESSAGE (1234) true 10000 1.0E-4 2.0E-5 test")); - verify(mReader).getViewerString(eq(1234)); - } - - @Test - public void log_logcatEnabledInlineMessage() { - when(mReader.getViewerString(anyInt())).thenReturn("test %d"); - ProtoLogImpl implSpy = Mockito.spy(mProtoLog); - TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); - TestProtoLogGroup.TEST_GROUP.setLogToProto(false); - - implSpy.log( - ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d", - new Object[]{5}); - - verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( - ProtoLogImpl.LogLevel.INFO), eq("test 5")); - verify(mReader, never()).getViewerString(anyInt()); - } - - @Test - public void log_logcatEnabledNoMessage() { - when(mReader.getViewerString(anyInt())).thenReturn(null); - ProtoLogImpl implSpy = Mockito.spy(mProtoLog); - TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true); - TestProtoLogGroup.TEST_GROUP.setLogToProto(false); - - implSpy.log( - ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null, - new Object[]{5}); - - verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq( - ProtoLogImpl.LogLevel.INFO), eq("UNKNOWN MESSAGE (1234) 5")); - verify(mReader).getViewerString(eq(1234)); - } - - @Test - public void log_logcatDisabled() { - when(mReader.getViewerString(anyInt())).thenReturn("test %d"); - ProtoLogImpl implSpy = Mockito.spy(mProtoLog); - TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false); - TestProtoLogGroup.TEST_GROUP.setLogToProto(false); - - implSpy.log( - ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d", - new Object[]{5}); - - verify(implSpy, never()).passToLogcat(any(), any(), any()); - verify(mReader, never()).getViewerString(anyInt()); - } - - private static class ProtoLogData { - Integer mMessageHash = null; - Long mElapsedTime = null; - LinkedList<String> mStrParams = new LinkedList<>(); - LinkedList<Long> mSint64Params = new LinkedList<>(); - LinkedList<Double> mDoubleParams = new LinkedList<>(); - LinkedList<Boolean> mBooleanParams = new LinkedList<>(); - } - - private ProtoLogData readProtoLogSingle(ProtoInputStream ip) throws IOException { - while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) { - if (ip.getFieldNumber() == (int) ProtoLogFileProto.VERSION) { - assertEquals(PROTOLOG_VERSION, ip.readString(ProtoLogFileProto.VERSION)); - continue; - } - if (ip.getFieldNumber() != (int) ProtoLogFileProto.LOG) { - continue; - } - long token = ip.start(ProtoLogFileProto.LOG); - ProtoLogData data = new ProtoLogData(); - while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) { - switch (ip.getFieldNumber()) { - case (int) ProtoLogMessage.MESSAGE_HASH: { - data.mMessageHash = ip.readInt(ProtoLogMessage.MESSAGE_HASH); - break; - } - case (int) ProtoLogMessage.ELAPSED_REALTIME_NANOS: { - data.mElapsedTime = ip.readLong(ProtoLogMessage.ELAPSED_REALTIME_NANOS); - break; - } - case (int) ProtoLogMessage.STR_PARAMS: { - data.mStrParams.add(ip.readString(ProtoLogMessage.STR_PARAMS)); - break; - } - case (int) ProtoLogMessage.SINT64_PARAMS: { - data.mSint64Params.add(ip.readLong(ProtoLogMessage.SINT64_PARAMS)); - break; - } - case (int) ProtoLogMessage.DOUBLE_PARAMS: { - data.mDoubleParams.add(ip.readDouble(ProtoLogMessage.DOUBLE_PARAMS)); - break; - } - case (int) ProtoLogMessage.BOOLEAN_PARAMS: { - data.mBooleanParams.add(ip.readBoolean(ProtoLogMessage.BOOLEAN_PARAMS)); - break; - } - } - } - ip.end(token); - return data; - } - return null; - } - - @Test - public void log_protoEnabled() throws Exception { - TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false); - TestProtoLogGroup.TEST_GROUP.setLogToProto(true); - mProtoLog.startProtoLog(mock(PrintWriter.class)); - long before = SystemClock.elapsedRealtimeNanos(); - mProtoLog.log( - ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, - 0b1110101001010100, null, - new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true}); - long after = SystemClock.elapsedRealtimeNanos(); - mProtoLog.stopProtoLog(mock(PrintWriter.class), true); - try (InputStream is = new FileInputStream(mFile)) { - ProtoInputStream ip = new ProtoInputStream(is); - ProtoLogData data = readProtoLogSingle(ip); - assertNotNull(data); - assertEquals(1234, data.mMessageHash.longValue()); - assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after); - assertArrayEquals(new String[]{"test"}, data.mStrParams.toArray()); - assertArrayEquals(new Long[]{1L, 2L, 3L}, data.mSint64Params.toArray()); - assertArrayEquals(new Double[]{0.4, 0.5, 0.6}, data.mDoubleParams.toArray()); - assertArrayEquals(new Boolean[]{true}, data.mBooleanParams.toArray()); - } - } - - @Test - public void log_invalidParamsMask() throws Exception { - TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false); - TestProtoLogGroup.TEST_GROUP.setLogToProto(true); - mProtoLog.startProtoLog(mock(PrintWriter.class)); - long before = SystemClock.elapsedRealtimeNanos(); - mProtoLog.log( - ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, - 0b01100100, null, - new Object[]{"test", 1, 0.1, true}); - long after = SystemClock.elapsedRealtimeNanos(); - mProtoLog.stopProtoLog(mock(PrintWriter.class), true); - try (InputStream is = new FileInputStream(mFile)) { - ProtoInputStream ip = new ProtoInputStream(is); - ProtoLogData data = readProtoLogSingle(ip); - assertNotNull(data); - assertEquals(1234, data.mMessageHash.longValue()); - assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after); - assertArrayEquals(new String[]{"test", "(INVALID PARAMS_MASK) true"}, - data.mStrParams.toArray()); - assertArrayEquals(new Long[]{1L}, data.mSint64Params.toArray()); - assertArrayEquals(new Double[]{0.1}, data.mDoubleParams.toArray()); - assertArrayEquals(new Boolean[]{}, data.mBooleanParams.toArray()); - } - } - - @Test - public void log_protoDisabled() throws Exception { - TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false); - TestProtoLogGroup.TEST_GROUP.setLogToProto(false); - mProtoLog.startProtoLog(mock(PrintWriter.class)); - mProtoLog.log(ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, - 0b11, null, new Object[]{true}); - mProtoLog.stopProtoLog(mock(PrintWriter.class), true); - try (InputStream is = new FileInputStream(mFile)) { - ProtoInputStream ip = new ProtoInputStream(is); - ProtoLogData data = readProtoLogSingle(ip); - assertNull(data); - } + eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{})); } private enum TestProtoLogGroup implements IProtoLogGroup { diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java index ae5021638745..dbd85d38b7f2 100644 --- a/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java +++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java @@ -72,8 +72,8 @@ public class ProtoLogViewerConfigReaderTest { + "}\n"; - private ProtoLogViewerConfigReader - mConfig = new ProtoLogViewerConfigReader(); + private LegacyProtoLogViewerConfigReader + mConfig = new LegacyProtoLogViewerConfigReader(); private File mTestViewerConfig; @Before @@ -98,7 +98,7 @@ public class ProtoLogViewerConfigReaderTest { @Test public void loadViewerConfig() { - mConfig.loadViewerConfig(null, mTestViewerConfig.getAbsolutePath()); + mConfig.loadViewerConfig(msg -> {}, mTestViewerConfig.getAbsolutePath()); assertEquals("Test completed successfully: %b", mConfig.getViewerString(70933285)); assertEquals("Test 2", mConfig.getViewerString(1352021864)); assertEquals("Window %s is already added", mConfig.getViewerString(409412266)); @@ -107,7 +107,7 @@ public class ProtoLogViewerConfigReaderTest { @Test public void loadViewerConfig_invalidFile() { - mConfig.loadViewerConfig(null, "/tmp/unknown/file/does/not/exist"); + mConfig.loadViewerConfig(msg -> {}, "/tmp/unknown/file/does/not/exist"); // No exception is thrown. assertNull(mConfig.getViewerString(1)); } diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt index 97398dc4e334..c2583475e484 100644 --- a/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt +++ b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt @@ -15,7 +15,7 @@ */ package com.android.test -import android.tools.common.flicker.subject.layers.LayersTraceSubject +import android.tools.flicker.subject.layers.LayersTraceSubject import junit.framework.Assert.assertEquals import junit.framework.Assert.assertTrue import org.junit.Test diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt index 0cc18d657cf5..0e70df4cb113 100644 --- a/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt +++ b/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt @@ -16,7 +16,7 @@ package com.android.test import android.graphics.Point -import android.tools.common.flicker.subject.layers.LayersTraceSubject +import android.tools.flicker.subject.layers.LayersTraceSubject import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode import com.android.test.SurfaceViewBufferTestBase.Companion.Transform import junit.framework.Assert.assertEquals diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt index 6f4d11c3aa1b..85024749746a 100644 --- a/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt +++ b/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt @@ -19,7 +19,7 @@ import android.graphics.Color import android.graphics.Point import android.graphics.Rect import android.os.SystemClock -import android.tools.common.flicker.subject.layers.LayersTraceSubject +import android.tools.flicker.subject.layers.LayersTraceSubject import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode import com.android.test.SurfaceViewBufferTestBase.Companion.Transform import junit.framework.Assert.assertEquals diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt index 1de965ebcb36..ad8b35ea8aa3 100644 --- a/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt +++ b/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt @@ -16,7 +16,7 @@ package com.android.test import android.graphics.Point -import android.tools.common.flicker.subject.layers.LayersTraceSubject +import android.tools.flicker.subject.layers.LayersTraceSubject import com.android.test.SurfaceViewBufferTestBase.Companion.Transform import junit.framework.Assert.assertEquals import org.junit.Assert diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt index 4c5224a8b151..b2ceb40b5e2f 100644 --- a/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt +++ b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt @@ -17,7 +17,7 @@ package com.android.test import android.graphics.Color import android.graphics.Rect -import android.tools.common.flicker.subject.layers.LayersTraceSubject +import android.tools.flicker.subject.layers.LayersTraceSubject import junit.framework.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt index b03b7335b08b..6e777960a475 100644 --- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt +++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt @@ -21,9 +21,9 @@ import android.graphics.Color import android.graphics.Rect import android.util.Log import androidx.test.ext.junit.rules.ActivityScenarioRule -import android.tools.common.traces.surfaceflinger.LayersTrace -import android.tools.device.traces.monitors.withSFTracing -import android.tools.device.traces.monitors.PerfettoTraceMonitor +import android.tools.traces.surfaceflinger.LayersTrace +import android.tools.traces.monitors.withSFTracing +import android.tools.traces.monitors.PerfettoTraceMonitor import junit.framework.Assert import org.junit.After import org.junit.Before diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt index 1770e32a5145..e0b180955419 100644 --- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt +++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt @@ -18,8 +18,8 @@ package com.android.test import android.app.Instrumentation import android.graphics.Point import android.provider.Settings -import android.tools.common.datatypes.Size -import android.tools.common.flicker.subject.layers.LayerSubject +import android.tools.datatypes.Size +import android.tools.flicker.subject.layers.LayerSubject import androidx.test.InstrumentationRegistry import org.junit.After import org.junit.Before diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt index 2c7905d552f1..e76a399cc159 100644 --- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt +++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt @@ -20,9 +20,9 @@ import android.graphics.Rect import androidx.test.ext.junit.rules.ActivityScenarioRule import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 -import android.tools.common.datatypes.Size -import android.tools.common.flicker.subject.layers.LayersTraceSubject -import android.tools.device.traces.monitors.withSFTracing +import android.tools.datatypes.Size +import android.tools.flicker.subject.layers.LayersTraceSubject +import android.tools.traces.monitors.withSFTracing import org.junit.After import org.junit.Before import org.junit.FixMethodOrder diff --git a/tools/hoststubgen/TEST_MAPPING b/tools/hoststubgen/TEST_MAPPING index eca258c5a74d..b5d5b5fb6d92 100644 --- a/tools/hoststubgen/TEST_MAPPING +++ b/tools/hoststubgen/TEST_MAPPING @@ -1,6 +1,7 @@ { "presubmit": [ - { "name": "tiny-framework-dump-test" }, + // TODO(b/326897452): Reenable after JDK 21 switch. + // { "name": "tiny-framework-dump-test" }, { "name": "hoststubgentest" }, { "name": "hoststubgen-invoke-test" } ], diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp index 46745e995f64..8fbc3e8a78db 100644 --- a/tools/protologtool/Android.bp +++ b/tools/protologtool/Android.bp @@ -11,12 +11,13 @@ java_library_host { name: "protologtool-lib", srcs: [ "src/com/android/protolog/tool/**/*.kt", - ":protolog-common-no-android-src", + ":protolog-common-src", ], static_libs: [ "javaparser", "platformprotos", "jsonlib", + "perfetto_trace-full", ], } @@ -42,5 +43,6 @@ java_test_host { "junit", "mockito", "objenesis", + "truth", ], } diff --git a/tools/protologtool/README.md b/tools/protologtool/README.md index ba639570f88c..24a4861c63a2 100644 --- a/tools/protologtool/README.md +++ b/tools/protologtool/README.md @@ -8,11 +8,13 @@ ProtoLogTool incorporates three different modes of operation: ### Code transformation -Command: `protologtool transform-protolog-calls - --protolog-class <protolog class name> - --protolog-impl-class <protolog implementation class name> +Command: `protologtool transform-protolog-calls + --protolog-class <protolog class name> --loggroups-class <protolog groups class name> --loggroups-jar <config jar path> + --viewer-config-file-path <protobuf viewer config file path> + --legacy-viewer-config-file-path <legacy json.gz viewer config file path> + --legacy-output-file-path <.winscope file path to write the legacy trace to> --output-srcjar <output.srcjar> [<input.java>]` @@ -44,10 +46,11 @@ jar file (config.jar). ### Viewer config generation Command: `generate-viewer-config - --protolog-class <protolog class name> + --protolog-class <protolog class name> --loggroups-class <protolog groups class name> --loggroups-jar <config jar path> - --viewer-conf <viewer.json> + --viewer-config-type <proto|json> + --viewer-config <viewer.json> [<input.java>]` This command is similar in it's syntax to the previous one, only instead of creating a processed source jar @@ -74,7 +77,7 @@ it writes a viewer configuration file with following schema: ### Binary log viewing -Command: `read-log --viewer-conf <viewer.json> <wm_log.pb>` +Command: `read-log --viewer-config <viewer.json> <wm_log.pb>` Reads the binary ProtoLog log file and outputs a human-readable LogCat-like text log. diff --git a/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt b/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt index 07c6fd328318..3d1dec2e0724 100644 --- a/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt +++ b/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt @@ -22,15 +22,21 @@ import com.github.javaparser.ast.ImportDeclaration import com.github.javaparser.ast.expr.BinaryExpr import com.github.javaparser.ast.expr.Expression import com.github.javaparser.ast.expr.StringLiteralExpr +import java.util.UUID object CodeUtils { /** * Returns a stable hash of a string. * We reimplement String::hashCode() for readability reasons. */ - fun hash(position: String, messageString: String, logLevel: LogLevel, logGroup: LogGroup): Int { - return (position + messageString + logLevel.name + logGroup.name) - .map { c -> c.code }.reduce { h, c -> h * 31 + c } + fun hash( + position: String, + messageString: String, + logLevel: LogLevel, + logGroup: LogGroup + ): Long { + val fullStringIdentifier = position + messageString + logLevel.name + logGroup.name + return UUID.nameUUIDFromBytes(fullStringIdentifier.toByteArray()).mostSignificantBits } fun checkWildcardStaticImported(code: CompilationUnit, className: String, fileName: String) { diff --git a/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt b/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt index bfbbf7a32c22..a3591558bd67 100644 --- a/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt +++ b/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt @@ -26,32 +26,35 @@ class CommandOptions(args: Array<String>) { private val commands = setOf(TRANSFORM_CALLS_CMD, GENERATE_CONFIG_CMD, READ_LOG_CMD) private const val PROTOLOG_CLASS_PARAM = "--protolog-class" - private const val PROTOLOGIMPL_CLASS_PARAM = "--protolog-impl-class" - private const val PROTOLOGCACHE_CLASS_PARAM = "--protolog-cache-class" private const val PROTOLOGGROUP_CLASS_PARAM = "--loggroups-class" private const val PROTOLOGGROUP_JAR_PARAM = "--loggroups-jar" - private const val VIEWER_CONFIG_JSON_PARAM = "--viewer-conf" + private const val VIEWER_CONFIG_PARAM = "--viewer-config" + private const val VIEWER_CONFIG_TYPE_PARAM = "--viewer-config-type" private const val OUTPUT_SOURCE_JAR_PARAM = "--output-srcjar" - private val parameters = setOf(PROTOLOG_CLASS_PARAM, PROTOLOGIMPL_CLASS_PARAM, - PROTOLOGCACHE_CLASS_PARAM, PROTOLOGGROUP_CLASS_PARAM, PROTOLOGGROUP_JAR_PARAM, - VIEWER_CONFIG_JSON_PARAM, OUTPUT_SOURCE_JAR_PARAM) + private const val VIEWER_CONFIG_FILE_PATH_PARAM = "--viewer-config-file-path" + // TODO(b/324128613): Remove these legacy options once we fully flip the Perfetto protolog flag + private const val LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM = "--legacy-viewer-config-file-path" + private const val LEGACY_OUTPUT_FILE_PATH = "--legacy-output-file-path" + private val parameters = setOf(PROTOLOG_CLASS_PARAM, PROTOLOGGROUP_CLASS_PARAM, + PROTOLOGGROUP_JAR_PARAM, VIEWER_CONFIG_PARAM, VIEWER_CONFIG_TYPE_PARAM, + OUTPUT_SOURCE_JAR_PARAM, VIEWER_CONFIG_FILE_PATH_PARAM, + LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM, LEGACY_OUTPUT_FILE_PATH) val USAGE = """ Usage: ${Constants.NAME} <command> [<args>] Available commands: - $TRANSFORM_CALLS_CMD $PROTOLOG_CLASS_PARAM <class name> $PROTOLOGIMPL_CLASS_PARAM - <class name> $PROTOLOGCACHE_CLASS_PARAM - <class name> $PROTOLOGGROUP_CLASS_PARAM <class name> $PROTOLOGGROUP_JAR_PARAM - <config.jar> $OUTPUT_SOURCE_JAR_PARAM <output.srcjar> [<input.java>] + $TRANSFORM_CALLS_CMD $PROTOLOG_CLASS_PARAM <class name> + $PROTOLOGGROUP_CLASS_PARAM <class name> $PROTOLOGGROUP_JAR_PARAM <config.jar> + $OUTPUT_SOURCE_JAR_PARAM <output.srcjar> [<input.java>] - processes java files replacing stub calls with logging code. - $GENERATE_CONFIG_CMD $PROTOLOG_CLASS_PARAM <class name> $PROTOLOGGROUP_CLASS_PARAM - <class name> $PROTOLOGGROUP_JAR_PARAM <config.jar> $VIEWER_CONFIG_JSON_PARAM - <viewer.json> [<input.java>] + $GENERATE_CONFIG_CMD $PROTOLOG_CLASS_PARAM <class name> + $PROTOLOGGROUP_CLASS_PARAM <class name> $PROTOLOGGROUP_JAR_PARAM <config.jar> + $VIEWER_CONFIG_PARAM <viewer.json|viewer.pb> [<input.java>] - creates viewer config file from given java files. - $READ_LOG_CMD $VIEWER_CONFIG_JSON_PARAM <viewer.json> <wm_log.pb> + $READ_LOG_CMD $VIEWER_CONFIG_PARAM <viewer.json|viewer.pb> <wm_log.pb> - translates a binary log to a readable format. """.trimIndent() @@ -69,6 +72,13 @@ class CommandOptions(args: Array<String>) { return params.getValue(paramName) } + private fun getOptionalParam(paramName: String, params: Map<String, String>): String? { + if (!params.containsKey(paramName)) { + return null + } + return params.getValue(paramName) + } + private fun validateNotSpecified(paramName: String, params: Map<String, String>): String { if (params.containsKey(paramName)) { throw InvalidCommandException("Unsupported param $paramName") @@ -90,9 +100,43 @@ class CommandOptions(args: Array<String>) { return name } - private fun validateJSONName(name: String): String { - if (!name.endsWith(".json")) { - throw InvalidCommandException("Json file required, got $name instead") + private fun validateViewerConfigFilePath(name: String): String { + if (!name.endsWith(".pb")) { + throw InvalidCommandException("Proto file (ending with .pb) required, " + + "got $name instead") + } + return name + } + + private fun validateLegacyViewerConfigFilePath(name: String): String { + if (!name.endsWith(".json.gz")) { + throw InvalidCommandException("GZiped Json file (ending with .json.gz) required, " + + "got $name instead") + } + return name + } + + private fun validateOutputFilePath(name: String): String { + if (!name.endsWith(".winscope")) { + throw InvalidCommandException("Winscope file (ending with .winscope) required, " + + "got $name instead") + } + return name + } + + private fun validateConfigFileName(name: String): String { + if (!name.endsWith(".json") && !name.endsWith(".pb")) { + throw InvalidCommandException("Json file (ending with .json) or proto file " + + "(ending with .pb) required, got $name instead") + } + return name + } + + private fun validateConfigType(name: String): String { + val validType = listOf("json", "proto") + if (!validType.contains(name)) { + throw InvalidCommandException("Unexpected config file type. " + + "Expected on of [${validType.joinToString()}], but got $name") } return name } @@ -102,8 +146,8 @@ class CommandOptions(args: Array<String>) { throw InvalidCommandException("No java source input files") } list.forEach { name -> - if (!name.endsWith(".java")) { - throw InvalidCommandException("Not a java source file $name") + if (!name.endsWith(".java") && !name.endsWith(".kt")) { + throw InvalidCommandException("Not a java or kotlin source file $name") } } return list @@ -122,12 +166,14 @@ class CommandOptions(args: Array<String>) { val protoLogClassNameArg: String val protoLogGroupsClassNameArg: String - val protoLogImplClassNameArg: String - val protoLogCacheClassNameArg: String val protoLogGroupsJarArg: String - val viewerConfigJsonArg: String + val viewerConfigFileNameArg: String + val viewerConfigTypeArg: String val outputSourceJarArg: String val logProtofileArg: String + val viewerConfigFilePathArg: String + val legacyViewerConfigFilePathArg: String? + val legacyOutputFilePath: String? val javaSourceArgs: List<String> val command: String @@ -169,38 +215,55 @@ class CommandOptions(args: Array<String>) { when (command) { TRANSFORM_CALLS_CMD -> { protoLogClassNameArg = validateClassName(getParam(PROTOLOG_CLASS_PARAM, params)) - protoLogGroupsClassNameArg = validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM, - params)) - protoLogImplClassNameArg = validateClassName(getParam(PROTOLOGIMPL_CLASS_PARAM, - params)) - protoLogCacheClassNameArg = validateClassName(getParam(PROTOLOGCACHE_CLASS_PARAM, - params)) + protoLogGroupsClassNameArg = + validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM, params)) protoLogGroupsJarArg = validateJarName(getParam(PROTOLOGGROUP_JAR_PARAM, params)) - viewerConfigJsonArg = validateNotSpecified(VIEWER_CONFIG_JSON_PARAM, params) + viewerConfigFileNameArg = validateNotSpecified(VIEWER_CONFIG_PARAM, params) + viewerConfigTypeArg = validateNotSpecified(VIEWER_CONFIG_TYPE_PARAM, params) outputSourceJarArg = validateSrcJarName(getParam(OUTPUT_SOURCE_JAR_PARAM, params)) + viewerConfigFilePathArg = validateViewerConfigFilePath( + getParam(VIEWER_CONFIG_FILE_PATH_PARAM, params)) + legacyViewerConfigFilePathArg = + getOptionalParam(LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM, params)?.let { + validateLegacyViewerConfigFilePath(it) + } + legacyOutputFilePath = + getOptionalParam(LEGACY_OUTPUT_FILE_PATH, params)?.let { + validateOutputFilePath(it) + } javaSourceArgs = validateJavaInputList(inputFiles) logProtofileArg = "" } GENERATE_CONFIG_CMD -> { protoLogClassNameArg = validateClassName(getParam(PROTOLOG_CLASS_PARAM, params)) - protoLogGroupsClassNameArg = validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM, - params)) - protoLogImplClassNameArg = validateNotSpecified(PROTOLOGIMPL_CLASS_PARAM, params) - protoLogCacheClassNameArg = validateNotSpecified(PROTOLOGCACHE_CLASS_PARAM, params) + protoLogGroupsClassNameArg = + validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM, params)) protoLogGroupsJarArg = validateJarName(getParam(PROTOLOGGROUP_JAR_PARAM, params)) - viewerConfigJsonArg = validateJSONName(getParam(VIEWER_CONFIG_JSON_PARAM, params)) + viewerConfigFileNameArg = + validateConfigFileName(getParam(VIEWER_CONFIG_PARAM, params)) + viewerConfigTypeArg = validateConfigType(getParam(VIEWER_CONFIG_TYPE_PARAM, params)) outputSourceJarArg = validateNotSpecified(OUTPUT_SOURCE_JAR_PARAM, params) + viewerConfigFilePathArg = + validateNotSpecified(VIEWER_CONFIG_FILE_PATH_PARAM, params) + legacyViewerConfigFilePathArg = + validateNotSpecified(LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM, params) + legacyOutputFilePath = validateNotSpecified(LEGACY_OUTPUT_FILE_PATH, params) javaSourceArgs = validateJavaInputList(inputFiles) logProtofileArg = "" } READ_LOG_CMD -> { protoLogClassNameArg = validateNotSpecified(PROTOLOG_CLASS_PARAM, params) protoLogGroupsClassNameArg = validateNotSpecified(PROTOLOGGROUP_CLASS_PARAM, params) - protoLogImplClassNameArg = validateNotSpecified(PROTOLOGIMPL_CLASS_PARAM, params) - protoLogCacheClassNameArg = validateNotSpecified(PROTOLOGCACHE_CLASS_PARAM, params) protoLogGroupsJarArg = validateNotSpecified(PROTOLOGGROUP_JAR_PARAM, params) - viewerConfigJsonArg = validateJSONName(getParam(VIEWER_CONFIG_JSON_PARAM, params)) + viewerConfigFileNameArg = + validateConfigFileName(getParam(VIEWER_CONFIG_PARAM, params)) + viewerConfigTypeArg = validateNotSpecified(VIEWER_CONFIG_TYPE_PARAM, params) outputSourceJarArg = validateNotSpecified(OUTPUT_SOURCE_JAR_PARAM, params) + viewerConfigFilePathArg = + validateNotSpecified(VIEWER_CONFIG_FILE_PATH_PARAM, params) + legacyViewerConfigFilePathArg = + validateNotSpecified(LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM, params) + legacyOutputFilePath = validateNotSpecified(LEGACY_OUTPUT_FILE_PATH, params) javaSourceArgs = listOf() logProtofileArg = validateLogInputList(inputFiles) } diff --git a/tools/protologtool/src/com/android/protolog/tool/MethodCallVisitor.kt b/tools/protologtool/src/com/android/protolog/tool/MethodCallVisitor.kt new file mode 100644 index 000000000000..fda6351361bf --- /dev/null +++ b/tools/protologtool/src/com/android/protolog/tool/MethodCallVisitor.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.protolog.tool + +import com.github.javaparser.ast.expr.MethodCallExpr + +interface MethodCallVisitor { + fun processCall(call: MethodCallExpr) +} diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt index 9a76a6f84c2b..47724b7a9e1d 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,115 +16,13 @@ package com.android.protolog.tool -import com.android.internal.protolog.common.LogLevel import com.github.javaparser.ast.CompilationUnit -import com.github.javaparser.ast.Node -import com.github.javaparser.ast.expr.Expression -import com.github.javaparser.ast.expr.FieldAccessExpr -import com.github.javaparser.ast.expr.MethodCallExpr -import com.github.javaparser.ast.expr.NameExpr -/** - * Helper class for visiting all ProtoLog calls. - * For every valid call in the given {@code CompilationUnit} a {@code ProtoLogCallVisitor} callback - * is executed. - */ -open class ProtoLogCallProcessor( - private val protoLogClassName: String, - private val protoLogGroupClassName: String, - private val groupMap: Map<String, LogGroup> -) { - private val protoLogSimpleClassName = protoLogClassName.substringAfterLast('.') - private val protoLogGroupSimpleClassName = protoLogGroupClassName.substringAfterLast('.') - - private fun getLogGroupName( - expr: Expression, - isClassImported: Boolean, - staticImports: Set<String>, +interface ProtoLogCallProcessor { + fun process( + code: CompilationUnit, + logCallVisitor: ProtoLogCallVisitor?, + otherCallVisitor: MethodCallVisitor?, fileName: String - ): String { - val context = ParsingContext(fileName, expr) - return when (expr) { - is NameExpr -> when { - expr.nameAsString in staticImports -> expr.nameAsString - else -> - throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr", - context) - } - is FieldAccessExpr -> when { - expr.scope.toString() == protoLogGroupClassName - || isClassImported && - expr.scope.toString() == protoLogGroupSimpleClassName -> expr.nameAsString - else -> - throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr", - context) - } - else -> throw InvalidProtoLogCallException("Invalid group argument " + - "- must be ProtoLogGroup enum member reference: $expr", context) - } - } - - private fun isProtoCall( - call: MethodCallExpr, - isLogClassImported: Boolean, - staticLogImports: Collection<String> - ): Boolean { - return call.scope.isPresent && call.scope.get().toString() == protoLogClassName || - isLogClassImported && call.scope.isPresent && - call.scope.get().toString() == protoLogSimpleClassName || - !call.scope.isPresent && staticLogImports.contains(call.name.toString()) - } - - open fun process(code: CompilationUnit, callVisitor: ProtoLogCallVisitor?, fileName: String): - CompilationUnit { - CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName) - CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName) - - val isLogClassImported = CodeUtils.isClassImportedOrSamePackage(code, protoLogClassName) - val staticLogImports = CodeUtils.staticallyImportedMethods(code, protoLogClassName) - val isGroupClassImported = CodeUtils.isClassImportedOrSamePackage(code, - protoLogGroupClassName) - val staticGroupImports = CodeUtils.staticallyImportedMethods(code, protoLogGroupClassName) - - code.findAll(MethodCallExpr::class.java) - .filter { call -> - isProtoCall(call, isLogClassImported, staticLogImports) - }.forEach { call -> - val context = ParsingContext(fileName, call) - if (call.arguments.size < 2) { - throw InvalidProtoLogCallException("Method signature does not match " + - "any ProtoLog method: $call", context) - } - - val messageString = CodeUtils.concatMultilineString(call.getArgument(1), - context) - val groupNameArg = call.getArgument(0) - val groupName = - getLogGroupName(groupNameArg, isGroupClassImported, - staticGroupImports, fileName) - if (groupName !in groupMap) { - throw InvalidProtoLogCallException("Unknown group argument " + - "- not a ProtoLogGroup enum member: $call", context) - } - - callVisitor?.processCall(call, messageString, getLevelForMethodName( - call.name.toString(), call, context), groupMap.getValue(groupName)) - } - return code - } - - companion object { - fun getLevelForMethodName(name: String, node: Node, context: ParsingContext): LogLevel { - return when (name) { - "d" -> LogLevel.DEBUG - "v" -> LogLevel.VERBOSE - "i" -> LogLevel.INFO - "w" -> LogLevel.WARN - "e" -> LogLevel.ERROR - "wtf" -> LogLevel.WTF - else -> - throw InvalidProtoLogCallException("Unknown log level $name in $node", context) - } - } - } + ): CompilationUnit } diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt new file mode 100644 index 000000000000..1087ae6ee41d --- /dev/null +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2019 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.protolog.tool + +import com.android.internal.protolog.common.LogLevel +import com.github.javaparser.ast.CompilationUnit +import com.github.javaparser.ast.expr.Expression +import com.github.javaparser.ast.expr.FieldAccessExpr +import com.github.javaparser.ast.expr.MethodCallExpr +import com.github.javaparser.ast.expr.NameExpr + +/** + * Helper class for visiting all ProtoLog calls. + * For every valid call in the given {@code CompilationUnit} a {@code ProtoLogCallVisitor} callback + * is executed. + */ +class ProtoLogCallProcessorImpl( + private val protoLogClassName: String, + private val protoLogGroupClassName: String, + private val groupMap: Map<String, LogGroup> +) : ProtoLogCallProcessor { + private val protoLogSimpleClassName = protoLogClassName.substringAfterLast('.') + private val protoLogGroupSimpleClassName = protoLogGroupClassName.substringAfterLast('.') + + private fun getLogGroupName( + expr: Expression, + isClassImported: Boolean, + staticImports: Set<String>, + fileName: String + ): String { + val context = ParsingContext(fileName, expr) + return when (expr) { + is NameExpr -> when { + expr.nameAsString in staticImports -> expr.nameAsString + else -> + throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr", + context) + } + is FieldAccessExpr -> when { + expr.scope.toString() == protoLogGroupClassName || isClassImported && + expr.scope.toString() == protoLogGroupSimpleClassName -> expr.nameAsString + else -> + throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr", + context) + } + else -> throw InvalidProtoLogCallException("Invalid group argument " + + "- must be ProtoLogGroup enum member reference: $expr", context) + } + } + + private fun isProtoCall( + call: MethodCallExpr, + isLogClassImported: Boolean, + staticLogImports: Collection<String> + ): Boolean { + return call.scope.isPresent && call.scope.get().toString() == protoLogClassName || + isLogClassImported && call.scope.isPresent && + call.scope.get().toString() == protoLogSimpleClassName || + !call.scope.isPresent && staticLogImports.contains(call.name.toString()) + } + + fun process(code: CompilationUnit, logCallVisitor: ProtoLogCallVisitor?, fileName: String): + CompilationUnit { + return process(code, logCallVisitor, null, fileName) + } + + override fun process( + code: CompilationUnit, + logCallVisitor: ProtoLogCallVisitor?, + otherCallVisitor: MethodCallVisitor?, + fileName: String + ): CompilationUnit { + CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName) + CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName) + + val isLogClassImported = CodeUtils.isClassImportedOrSamePackage(code, protoLogClassName) + val staticLogImports = CodeUtils.staticallyImportedMethods(code, protoLogClassName) + val isGroupClassImported = CodeUtils.isClassImportedOrSamePackage(code, + protoLogGroupClassName) + val staticGroupImports = CodeUtils.staticallyImportedMethods(code, protoLogGroupClassName) + + code.findAll(MethodCallExpr::class.java) + .filter { call -> + isProtoCall(call, isLogClassImported, staticLogImports) + }.forEach { call -> + val context = ParsingContext(fileName, call) + + val logMethods = LogLevel.entries.map { it.shortCode } + if (logMethods.contains(call.name.id)) { + // Process a log call + if (call.arguments.size < 2) { + throw InvalidProtoLogCallException("Method signature does not match " + + "any ProtoLog method: $call", context) + } + + val messageString = CodeUtils.concatMultilineString(call.getArgument(1), + context) + val groupNameArg = call.getArgument(0) + val groupName = + getLogGroupName(groupNameArg, isGroupClassImported, + staticGroupImports, fileName) + if (groupName !in groupMap) { + throw InvalidProtoLogCallException("Unknown group argument " + + "- not a ProtoLogGroup enum member: $call", context) + } + + logCallVisitor?.processCall(call, messageString, getLevelForMethodName( + call.name.toString(), call, context), groupMap.getValue(groupName)) + } else { + // Process non-log message calls + otherCallVisitor?.processCall(call) + } + } + return code + } + + private fun getLevelForMethodName( + name: String, + node: MethodCallExpr, + context: ParsingContext + ): LogLevel = when (name) { + "d" -> LogLevel.DEBUG + "v" -> LogLevel.VERBOSE + "i" -> LogLevel.INFO + "w" -> LogLevel.WARN + "e" -> LogLevel.ERROR + "wtf" -> LogLevel.WTF + else -> + throw InvalidProtoLogCallException("Unknown log level $name in $node", context) + } +} diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt index ce856cd49614..1381847c258f 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt @@ -16,13 +16,22 @@ package com.android.protolog.tool +import com.android.internal.protolog.common.LogLevel +import com.android.internal.protolog.common.ProtoLog +import com.android.internal.protolog.common.ProtoLogToolInjected import com.android.protolog.tool.CommandOptions.Companion.USAGE import com.github.javaparser.ParseProblemException import com.github.javaparser.ParserConfiguration import com.github.javaparser.StaticJavaParser import com.github.javaparser.ast.CompilationUnit +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration +import com.github.javaparser.ast.expr.MethodCallExpr +import com.github.javaparser.ast.expr.NullLiteralExpr +import com.github.javaparser.ast.expr.SimpleName +import com.github.javaparser.ast.expr.StringLiteralExpr import java.io.File import java.io.FileInputStream +import java.io.FileNotFoundException import java.io.FileOutputStream import java.io.OutputStream import java.time.LocalDateTime @@ -30,9 +39,21 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import java.util.jar.JarOutputStream import java.util.zip.ZipEntry +import kotlin.math.abs +import kotlin.random.Random import kotlin.system.exitProcess object ProtoLogTool { + const val PROTOLOG_IMPL_SRC_PATH = + "frameworks/base/core/java/com/android/internal/protolog/ProtoLogImpl.java" + + data class LogCall( + val messageString: String, + val logLevel: LogLevel, + val logGroup: LogGroup, + val position: String + ) + private fun showHelpAndExit() { println(USAGE) exitProcess(-1) @@ -51,26 +72,40 @@ object ProtoLogTool { } private fun processClasses(command: CommandOptions) { + val generationHash = abs(Random.nextInt()) + // Need to generate a new impl class to inject static constants into the class. + val generatedProtoLogImplClass = + "com.android.internal.protolog.ProtoLogImpl_$generationHash" + val groups = injector.readLogGroups( command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg) val out = injector.fileOutputStream(command.outputSourceJarArg) val outJar = JarOutputStream(out) - val processor = ProtoLogCallProcessor(command.protoLogClassNameArg, - command.protoLogGroupsClassNameArg, groups) + val processor = ProtoLogCallProcessorImpl( + command.protoLogClassNameArg, + command.protoLogGroupsClassNameArg, + groups) + + val protologImplName = generatedProtoLogImplClass.split(".").last() + val protologImplPath = "gen/${generatedProtoLogImplClass.split(".") + .joinToString("/")}.java" + outJar.putNextEntry(zipEntry(protologImplPath)) + + outJar.write(generateProtoLogImpl(protologImplName, command.viewerConfigFilePathArg, + command.legacyViewerConfigFilePathArg, command.legacyOutputFilePath).toByteArray()) val executor = newThreadPool() try { command.javaSourceArgs.map { path -> executor.submitCallable { - val transformer = SourceTransformer(command.protoLogImplClassNameArg, - command.protoLogCacheClassNameArg, processor) + val transformer = SourceTransformer(generatedProtoLogImplClass, processor) val file = File(path) val text = injector.readText(file) val outSrc = try { val code = tryParse(text, path) - if (containsProtoLogText(text, command.protoLogClassNameArg)) { + if (containsProtoLogText(text, ProtoLog::class.java.simpleName)) { transformer.processClass(text, path, packagePath(file, code), code) } else { text @@ -93,51 +128,77 @@ object ProtoLogTool { executor.shutdown() } - val cacheSplit = command.protoLogCacheClassNameArg.split(".") - val cacheName = cacheSplit.last() - val cachePackage = cacheSplit.dropLast(1).joinToString(".") - val cachePath = "gen/${cacheSplit.joinToString("/")}.java" - - outJar.putNextEntry(zipEntry(cachePath)) - outJar.write(generateLogGroupCache(cachePackage, cacheName, groups, - command.protoLogImplClassNameArg, command.protoLogGroupsClassNameArg).toByteArray()) - outJar.close() out.close() } - fun generateLogGroupCache( - cachePackage: String, - cacheName: String, - groups: Map<String, LogGroup>, - protoLogImplClassName: String, - protoLogGroupsClassName: String + private fun generateProtoLogImpl( + protoLogImplGenName: String, + viewerConfigFilePath: String, + legacyViewerConfigFilePath: String?, + legacyOutputFilePath: String?, ): String { - val fields = groups.values.map { - "public static boolean ${it.name}_enabled = false;" - }.joinToString("\n") + val file = File(PROTOLOG_IMPL_SRC_PATH) - val updates = groups.values.map { - "${it.name}_enabled = " + - "$protoLogImplClassName.isEnabled($protoLogGroupsClassName.${it.name});" - }.joinToString("\n") + val text = try { + injector.readText(file) + } catch (e: FileNotFoundException) { + throw RuntimeException("Expected to find '$PROTOLOG_IMPL_SRC_PATH' but file was not " + + "included in source for the ProtoLog Tool to process.") + } - return """ - package $cachePackage; + val code = tryParse(text, PROTOLOG_IMPL_SRC_PATH) - public class $cacheName { -${fields.replaceIndent(" ")} + val classDeclarations = code.findAll(ClassOrInterfaceDeclaration::class.java) + require(classDeclarations.size == 1) { "Expected exactly one class declaration" } + val classDeclaration = classDeclarations[0] - static { - $protoLogImplClassName.sCacheUpdater = $cacheName::update; - update(); - } + val classNameNode = classDeclaration.findFirst(SimpleName::class.java).get() + classNameNode.setId(protoLogImplGenName) - static void update() { -${updates.replaceIndent(" ")} - } - } - """.trimIndent() + injectConstants(classDeclaration, + viewerConfigFilePath, legacyViewerConfigFilePath, legacyOutputFilePath) + + return code.toString() + } + + private fun injectConstants( + classDeclaration: ClassOrInterfaceDeclaration, + viewerConfigFilePath: String, + legacyViewerConfigFilePath: String?, + legacyOutputFilePath: String? + ) { + classDeclaration.fields.forEach { field -> + field.getAnnotationByClass(ProtoLogToolInjected::class.java) + .ifPresent { annotationExpr -> + if (annotationExpr.isSingleMemberAnnotationExpr) { + val valueName = annotationExpr.asSingleMemberAnnotationExpr() + .memberValue.asNameExpr().name.asString() + when (valueName) { + ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH.name -> { + field.setFinal(true) + field.variables.first() + .setInitializer(StringLiteralExpr(viewerConfigFilePath)) + } + ProtoLogToolInjected.Value.LEGACY_OUTPUT_FILE_PATH.name -> { + field.setFinal(true) + field.variables.first() + .setInitializer(legacyOutputFilePath?.let { + StringLiteralExpr(it) + } ?: NullLiteralExpr()) + } + ProtoLogToolInjected.Value.LEGACY_VIEWER_CONFIG_PATH.name -> { + field.setFinal(true) + field.variables.first() + .setInitializer(legacyViewerConfigFilePath?.let { + StringLiteralExpr(it) + } ?: NullLiteralExpr()) + } + else -> error("Unhandled ProtoLogToolInjected value: $valueName.") + } + } + } + } } private fun tryParse(code: String, fileName: String): CompilationUnit { @@ -145,24 +206,53 @@ ${updates.replaceIndent(" ")} return StaticJavaParser.parse(code) } catch (ex: ParseProblemException) { val problem = ex.problems.first() - throw ParsingException("Java parsing erro" + - "r: ${problem.verboseMessage}", + throw ParsingException("Java parsing error: ${problem.verboseMessage}", ParsingContext(fileName, problem.location.orElse(null) ?.begin?.range?.orElse(null)?.begin?.line ?: 0)) } } + class LogCallRegistry { + private val statements = mutableMapOf<LogCall, Long>() + + fun addLogCalls(calls: List<LogCall>) { + calls.forEach { logCall -> + if (logCall.logGroup.enabled) { + statements.putIfAbsent(logCall, + CodeUtils.hash(logCall.position, logCall.messageString, + logCall.logLevel, logCall.logGroup)) + } + } + } + + fun getStatements(): Map<LogCall, Long> { + return statements + } + } + + interface ProtologViewerConfigBuilder { + fun build(statements: Map<LogCall, Long>): ByteArray + } + private fun viewerConf(command: CommandOptions) { val groups = injector.readLogGroups( command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg) - val processor = ProtoLogCallProcessor(command.protoLogClassNameArg, + val processor = ProtoLogCallProcessorImpl(command.protoLogClassNameArg, command.protoLogGroupsClassNameArg, groups) - val builder = ViewerConfigBuilder(processor) + val outputType = command.viewerConfigTypeArg + + val configBuilder: ProtologViewerConfigBuilder = when (outputType.lowercase()) { + "json" -> ViewerConfigJsonBuilder() + "proto" -> ViewerConfigProtoBuilder() + else -> error("Invalid output type provide. Provided '$outputType'.") + } val executor = newThreadPool() + val logCallRegistry = LogCallRegistry() + try { command.javaSourceArgs.map { path -> executor.submitCallable { @@ -171,7 +261,7 @@ ${updates.replaceIndent(" ")} if (containsProtoLogText(text, command.protoLogClassNameArg)) { try { val code = tryParse(text, path) - builder.findLogCalls(code, path, packagePath(file, code)) + findLogCalls(code, path, packagePath(file, code), processor) } catch (ex: ParsingException) { // If we cannot parse this file, skip it (and log why). Compilation will // fail in a subsequent build step. @@ -183,15 +273,38 @@ ${updates.replaceIndent(" ")} } } }.forEach { future -> - builder.addLogCalls(future.get() ?: return@forEach) + logCallRegistry.addLogCalls(future.get() ?: return@forEach) } } finally { executor.shutdown() } - val out = injector.fileOutputStream(command.viewerConfigJsonArg) - out.write(builder.build().toByteArray()) - out.close() + val outFile = injector.fileOutputStream(command.viewerConfigFileNameArg) + outFile.write(configBuilder.build(logCallRegistry.getStatements())) + outFile.close() + } + + private fun findLogCalls( + unit: CompilationUnit, + path: String, + packagePath: String, + processor: ProtoLogCallProcessorImpl + ): List<LogCall> { + val calls = mutableListOf<LogCall>() + val logCallVisitor = object : ProtoLogCallVisitor { + override fun processCall( + call: MethodCallExpr, + messageString: String, + level: LogLevel, + group: LogGroup + ) { + val logCall = LogCall(messageString, level, group, packagePath) + calls.add(logCall) + } + } + processor.process(unit, logCallVisitor, path) + + return calls } private fun packagePath(file: File, code: CompilationUnit): String { @@ -204,7 +317,7 @@ ${updates.replaceIndent(" ")} private fun read(command: CommandOptions) { LogParser(ViewerConfigParser()) .parse(FileInputStream(command.logProtofileArg), - FileInputStream(command.viewerConfigJsonArg), System.out) + FileInputStream(command.viewerConfigFileNameArg), System.out) } @JvmStatic diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt index b50f357c57ec..2b7164191dd0 100644 --- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt +++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt @@ -22,11 +22,11 @@ import com.github.javaparser.StaticJavaParser import com.github.javaparser.ast.CompilationUnit import com.github.javaparser.ast.NodeList import com.github.javaparser.ast.body.VariableDeclarator -import com.github.javaparser.ast.expr.BooleanLiteralExpr import com.github.javaparser.ast.expr.CastExpr import com.github.javaparser.ast.expr.Expression import com.github.javaparser.ast.expr.FieldAccessExpr import com.github.javaparser.ast.expr.IntegerLiteralExpr +import com.github.javaparser.ast.expr.LongLiteralExpr import com.github.javaparser.ast.expr.MethodCallExpr import com.github.javaparser.ast.expr.NameExpr import com.github.javaparser.ast.expr.NullLiteralExpr @@ -35,7 +35,6 @@ import com.github.javaparser.ast.expr.TypeExpr import com.github.javaparser.ast.expr.VariableDeclarationExpr import com.github.javaparser.ast.stmt.BlockStmt import com.github.javaparser.ast.stmt.ExpressionStmt -import com.github.javaparser.ast.stmt.IfStmt import com.github.javaparser.ast.type.ArrayType import com.github.javaparser.ast.type.ClassOrInterfaceType import com.github.javaparser.ast.type.PrimitiveType @@ -45,15 +44,59 @@ import com.github.javaparser.printer.PrettyPrinterConfiguration class SourceTransformer( protoLogImplClassName: String, - protoLogCacheClassName: String, private val protoLogCallProcessor: ProtoLogCallProcessor -) : ProtoLogCallVisitor { - override fun processCall( - call: MethodCallExpr, - messageString: String, - level: LogLevel, - group: LogGroup - ) { +) { + private val inlinePrinter: PrettyPrinter + private val objectType = StaticJavaParser.parseClassOrInterfaceType("Object") + + init { + val config = PrettyPrinterConfiguration() + config.endOfLineCharacter = " " + config.indentSize = 0 + config.tabWidth = 1 + inlinePrinter = PrettyPrinter(config) + } + + fun processClass( + code: String, + path: String, + packagePath: String, + compilationUnit: CompilationUnit = + StaticJavaParser.parse(code) + ): String { + this.path = path + this.packagePath = packagePath + processedCode = code.split('\n').toMutableList() + offsets = IntArray(processedCode.size) + protoLogCallProcessor.process(compilationUnit, protoLogCallVisitor, otherCallVisitor, path) + return processedCode.joinToString("\n") + } + + private val protoLogImplClassNode = + StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogImplClassName) + private var processedCode: MutableList<String> = mutableListOf() + private var offsets: IntArray = IntArray(0) + /** The path of the file being processed, relative to $ANDROID_BUILD_TOP */ + private var path: String = "" + /** The path of the file being processed, relative to the root package */ + private var packagePath: String = "" + + private val protoLogCallVisitor = object : ProtoLogCallVisitor { + override fun processCall( + call: MethodCallExpr, + messageString: String, + level: LogLevel, + group: LogGroup + ) { + validateCall(call) + val processedCallStatement = + createProcessedCallStatement(call, group, level, messageString) + val parentStmt = call.parentNode.get() as ExpressionStmt + injectProcessedCallStatementInCode(processedCallStatement, parentStmt) + } + } + + private fun validateCall(call: MethodCallExpr) { // Input format: ProtoLog.e(GROUP, "msg %d", arg) if (!call.parentNode.isPresent) { // Should never happen @@ -71,89 +114,79 @@ class SourceTransformer( throw RuntimeException("Unable to process log call $call " + "- no grandparent node in AST") } - val ifStmt: IfStmt - if (group.enabled) { - val hash = CodeUtils.hash(packagePath, messageString, level, group) - val newCall = call.clone() - if (!group.textEnabled) { - // Remove message string if text logging is not enabled by default. - // Out: ProtoLog.e(GROUP, null, arg) - newCall.arguments[1].replace(NameExpr("null")) - } - // Insert message string hash as a second argument. - // Out: ProtoLog.e(GROUP, 1234, null, arg) - newCall.arguments.add(1, IntegerLiteralExpr(hash)) - val argTypes = LogDataType.parseFormatString(messageString) - val typeMask = LogDataType.logDataTypesToBitMask(argTypes) - // Insert bitmap representing which Number parameters are to be considered as - // floating point numbers. - // Out: ProtoLog.e(GROUP, 1234, 0, null, arg) - newCall.arguments.add(2, IntegerLiteralExpr(typeMask)) - // Replace call to a stub method with an actual implementation. - // Out: ProtoLogImpl.e(GROUP, 1234, null, arg) - newCall.setScope(protoLogImplClassNode) - // Create a call to ProtoLog$Cache.GROUP_enabled - // Out: com.android.server.protolog.ProtoLog$Cache.GROUP_enabled - val isLogEnabled = FieldAccessExpr(protoLogCacheClassNode, "${group.name}_enabled") - if (argTypes.size != call.arguments.size - 2) { - throw InvalidProtoLogCallException( - "Number of arguments (${argTypes.size} does not mach format" + - " string in: $call", ParsingContext(path, call)) - } - val blockStmt = BlockStmt() - if (argTypes.isNotEmpty()) { - // Assign every argument to a variable to check its type in compile time - // (this is assignment is optimized-out by dex tool, there is no runtime impact)/ - // Out: long protoLogParam0 = arg - argTypes.forEachIndexed { idx, type -> - val varName = "protoLogParam$idx" - val declaration = VariableDeclarator(getASTTypeForDataType(type), varName, - getConversionForType(type)(newCall.arguments[idx + 4].clone())) - blockStmt.addStatement(ExpressionStmt(VariableDeclarationExpr(declaration))) - newCall.setArgument(idx + 4, NameExpr(SimpleName(varName))) - } - } else { - // Assign (Object[])null as the vararg parameter to prevent allocating an empty - // object array. - val nullArray = CastExpr(ArrayType(objectType), NullLiteralExpr()) - newCall.addArgument(nullArray) + } + + private fun createProcessedCallStatement( + call: MethodCallExpr, + group: LogGroup, + level: LogLevel, + messageString: String + ): BlockStmt { + val hash = CodeUtils.hash(packagePath, messageString, level, group) + val newCall = call.clone() + if (!group.textEnabled) { + // Remove message string if text logging is not enabled by default. + // Out: ProtoLog.e(GROUP, null, arg) + newCall.arguments[1].replace(NameExpr("null")) + } + // Insert message string hash as a second argument. + // Out: ProtoLog.e(GROUP, 1234, null, arg) + newCall.arguments.add(1, LongLiteralExpr("" + hash + "L")) + val argTypes = LogDataType.parseFormatString(messageString) + val typeMask = LogDataType.logDataTypesToBitMask(argTypes) + // Insert bitmap representing which Number parameters are to be considered as + // floating point numbers. + // Out: ProtoLog.e(GROUP, 1234, 0, null, arg) + newCall.arguments.add(2, IntegerLiteralExpr(typeMask)) + // Replace call to a stub method with an actual implementation. + // Out: ProtoLogImpl.e(GROUP, 1234, null, arg) + newCall.setScope(protoLogImplClassNode) + if (argTypes.size != call.arguments.size - 2) { + throw InvalidProtoLogCallException( + "Number of arguments (${argTypes.size} does not match format" + + " string in: $call", ParsingContext(path, call)) + } + val blockStmt = BlockStmt() + if (argTypes.isNotEmpty()) { + // Assign every argument to a variable to check its type in compile time + // (this is assignment is optimized-out by dex tool, there is no runtime impact)/ + // Out: long protoLogParam0 = arg + argTypes.forEachIndexed { idx, type -> + val varName = "protoLogParam$idx" + val declaration = VariableDeclarator(getASTTypeForDataType(type), varName, + getConversionForType(type)(newCall.arguments[idx + 4].clone())) + blockStmt.addStatement(ExpressionStmt(VariableDeclarationExpr(declaration))) + newCall.setArgument(idx + 4, NameExpr(SimpleName(varName))) } - blockStmt.addStatement(ExpressionStmt(newCall)) - // Create an IF-statement with the previously created condition. - // Out: if (ProtoLogImpl.isEnabled(GROUP)) { - // long protoLogParam0 = arg; - // ProtoLogImpl.e(GROUP, 1234, 0, null, protoLogParam0); - // } - ifStmt = IfStmt(isLogEnabled, blockStmt, null) } else { - // Surround with if (false). - val newCall = parentStmt.clone() - ifStmt = IfStmt(BooleanLiteralExpr(false), BlockStmt(NodeList(newCall)), null) - newCall.setBlockComment(" ${group.name} is disabled ") + // Assign (Object[])null as the vararg parameter to prevent allocating an empty + // object array. + val nullArray = CastExpr(ArrayType(objectType), NullLiteralExpr()) + newCall.addArgument(nullArray) } + blockStmt.addStatement(ExpressionStmt(newCall)) + + return blockStmt + } + + private fun injectProcessedCallStatementInCode( + processedCallStatement: BlockStmt, + parentStmt: ExpressionStmt + ) { // Inline the new statement. - val printedIfStmt = inlinePrinter.print(ifStmt) + val printedBlockStmt = inlinePrinter.print(processedCallStatement) // Append blank lines to preserve line numbering in file (to allow debugging) val parentRange = parentStmt.range.get() val newLines = parentRange.end.line - parentRange.begin.line - val newStmt = printedIfStmt.substringBeforeLast('}') + ("\n".repeat(newLines)) + '}' + val newStmt = printedBlockStmt.substringBeforeLast('}') + ("\n".repeat(newLines)) + '}' // pre-workaround code, see explanation below - /* - val inlinedIfStmt = StaticJavaParser.parseStatement(newStmt) - LexicalPreservingPrinter.setup(inlinedIfStmt) - // Replace the original call. - if (!parentStmt.replace(inlinedIfStmt)) { - // Should never happen - throw RuntimeException("Unable to process log call $call " + - "- unable to replace the call.") - } - */ + /** Workaround for a bug in JavaParser (AST tree invalid after replacing a node when using * LexicalPreservingPrinter (https://github.com/javaparser/javaparser/issues/2290). * Replace the code below with the one commended-out above one the issue is resolved. */ if (!parentStmt.range.isPresent) { // Should never happen - throw RuntimeException("Unable to process log call $call " + + throw RuntimeException("Unable to process log call in $parentStmt " + "- unable to replace the call.") } val range = parentStmt.range.get() @@ -161,29 +194,38 @@ class SourceTransformer( val oldLines = processedCode.subList(begin, range.end.line) val oldCode = oldLines.joinToString("\n") val newCode = oldCode.replaceRange( - offsets[begin] + range.begin.column - 1, - oldCode.length - oldLines.lastOrNull()!!.length + - range.end.column + offsets[range.end.line - 1], newStmt) + offsets[begin] + range.begin.column - 1, + oldCode.length - oldLines.lastOrNull()!!.length + + range.end.column + offsets[range.end.line - 1], newStmt) newCode.split("\n").forEachIndexed { idx, line -> offsets[begin + idx] += line.length - processedCode[begin + idx].length processedCode[begin + idx] = line } } - private val inlinePrinter: PrettyPrinter - private val objectType = StaticJavaParser.parseClassOrInterfaceType("Object") + private val otherCallVisitor = object : MethodCallVisitor { + override fun processCall(call: MethodCallExpr) { + val newCall = call.clone() + newCall.setScope(protoLogImplClassNode) - init { - val config = PrettyPrinterConfiguration() - config.endOfLineCharacter = " " - config.indentSize = 0 - config.tabWidth = 1 - inlinePrinter = PrettyPrinter(config) + val range = call.range.get() + val begin = range.begin.line - 1 + val oldLines = processedCode.subList(begin, range.end.line) + val oldCode = oldLines.joinToString("\n") + val newCode = oldCode.replaceRange( + offsets[begin] + range.begin.column - 1, + oldCode.length - oldLines.lastOrNull()!!.length + + range.end.column + offsets[range.end.line - 1], newCall.toString()) + newCode.split("\n").forEachIndexed { idx, line -> + offsets[begin + idx] += line.length - processedCode[begin + idx].length + processedCode[begin + idx] = line + } + } } companion object { private val stringType: ClassOrInterfaceType = - StaticJavaParser.parseClassOrInterfaceType("String") + StaticJavaParser.parseClassOrInterfaceType("String") fun getASTTypeForDataType(type: Int): Type { return when (type) { @@ -202,36 +244,10 @@ class SourceTransformer( return when (type) { LogDataType.STRING -> { expr -> MethodCallExpr(TypeExpr(StaticJavaParser.parseClassOrInterfaceType("String")), - SimpleName("valueOf"), NodeList(expr)) + SimpleName("valueOf"), NodeList(expr)) } else -> { expr -> expr } } } } - - private val protoLogImplClassNode = - StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogImplClassName) - private val protoLogCacheClassNode = - StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogCacheClassName) - private var processedCode: MutableList<String> = mutableListOf() - private var offsets: IntArray = IntArray(0) - /** The path of the file being processed, relative to $ANDROID_BUILD_TOP */ - private var path: String = "" - /** The path of the file being processed, relative to the root package */ - private var packagePath: String = "" - - fun processClass( - code: String, - path: String, - packagePath: String, - compilationUnit: CompilationUnit = - StaticJavaParser.parse(code) - ): String { - this.path = path - this.packagePath = packagePath - processedCode = code.split('\n').toMutableList() - offsets = IntArray(processedCode.size) - protoLogCallProcessor.process(compilationUnit, this, path) - return processedCode.joinToString("\n") - } } diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt deleted file mode 100644 index 0d5d022959b2..000000000000 --- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2019 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.protolog.tool - -import com.android.internal.protolog.common.LogLevel -import com.android.json.stream.JsonWriter -import com.github.javaparser.ast.CompilationUnit -import com.android.protolog.tool.Constants.VERSION -import com.github.javaparser.ast.expr.MethodCallExpr -import java.io.StringWriter - -class ViewerConfigBuilder( - private val processor: ProtoLogCallProcessor -) { - private fun addLogCall(logCall: LogCall, context: ParsingContext) { - val group = logCall.logGroup - val messageString = logCall.messageString - if (group.enabled) { - val key = logCall.key() - if (statements.containsKey(key)) { - if (statements[key] != logCall) { - throw HashCollisionException( - "Please modify the log message \"$messageString\" " + - "or \"${statements[key]}\" - their hashes are equal.", context) - } - } else { - groups.add(group) - statements[key] = logCall - } - } - } - - private val statements: MutableMap<Int, LogCall> = mutableMapOf() - private val groups: MutableSet<LogGroup> = mutableSetOf() - - fun findLogCalls( - unit: CompilationUnit, - path: String, - packagePath: String - ): List<Pair<LogCall, ParsingContext>> { - val calls = mutableListOf<Pair<LogCall, ParsingContext>>() - val visitor = object : ProtoLogCallVisitor { - override fun processCall( - call: MethodCallExpr, - messageString: String, - level: LogLevel, - group: LogGroup - ) { - val logCall = LogCall(messageString, level, group, packagePath) - val context = ParsingContext(path, call) - calls.add(logCall to context) - } - } - processor.process(unit, visitor, path) - - return calls - } - - fun addLogCalls(calls: List<Pair<LogCall, ParsingContext>>) { - calls.forEach { (logCall, context) -> - addLogCall(logCall, context) - } - } - - fun build(): String { - val stringWriter = StringWriter() - val writer = JsonWriter(stringWriter) - writer.setIndent(" ") - writer.beginObject() - writer.name("version") - writer.value(VERSION) - writer.name("messages") - writer.beginObject() - statements.toSortedMap().forEach { (key, value) -> - writer.name(key.toString()) - writer.beginObject() - writer.name("message") - writer.value(value.messageString) - writer.name("level") - writer.value(value.logLevel.name) - writer.name("group") - writer.value(value.logGroup.name) - writer.name("at") - writer.value(value.position) - writer.endObject() - } - writer.endObject() - writer.name("groups") - writer.beginObject() - groups.toSortedSet(Comparator { o1, o2 -> o1.name.compareTo(o2.name) }).forEach { group -> - writer.name(group.name) - writer.beginObject() - writer.name("tag") - writer.value(group.tag) - writer.endObject() - } - writer.endObject() - writer.endObject() - stringWriter.buffer.append('\n') - return stringWriter.toString() - } - - data class LogCall( - val messageString: String, - val logLevel: LogLevel, - val logGroup: LogGroup, - val position: String - ) { - fun key() = CodeUtils.hash(position, messageString, logLevel, logGroup) - } -} diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt new file mode 100644 index 000000000000..7714db212c9f --- /dev/null +++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.protolog.tool + +import com.android.json.stream.JsonWriter +import com.android.protolog.tool.Constants.VERSION +import java.io.StringWriter + +class ViewerConfigJsonBuilder : ProtoLogTool.ProtologViewerConfigBuilder { + override fun build(statements: Map<ProtoLogTool.LogCall, Long>): ByteArray { + val groups = statements.map { it.key.logGroup }.toSet() + val stringWriter = StringWriter() + val writer = JsonWriter(stringWriter) + writer.setIndent(" ") + writer.beginObject() + writer.name("version") + writer.value(VERSION) + writer.name("messages") + writer.beginObject() + statements.forEach { (log, key) -> + writer.name(key.toString()) + writer.beginObject() + writer.name("message") + writer.value(log.messageString) + writer.name("level") + writer.value(log.logLevel.name) + writer.name("group") + writer.value(log.logGroup.name) + writer.name("at") + writer.value(log.position) + writer.endObject() + } + writer.endObject() + writer.name("groups") + writer.beginObject() + groups.toSortedSet { o1, o2 -> o1.name.compareTo(o2.name) }.forEach { group -> + writer.name(group.name) + writer.beginObject() + writer.name("tag") + writer.value(group.tag) + writer.endObject() + } + writer.endObject() + writer.endObject() + stringWriter.buffer.append('\n') + return stringWriter.toString().toByteArray() + } +} diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt index 7278db0094e6..58be3a3e04af 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt @@ -63,12 +63,12 @@ open class ViewerConfigParser { return GroupEntry(tag) } - fun parseMessages(jsonReader: JsonReader): Map<Int, MessageEntry> { - val config: MutableMap<Int, MessageEntry> = mutableMapOf() + fun parseMessages(jsonReader: JsonReader): Map<Long, MessageEntry> { + val config: MutableMap<Long, MessageEntry> = mutableMapOf() jsonReader.beginObject() while (jsonReader.hasNext()) { val key = jsonReader.nextName() - val hash = key.toIntOrNull() + val hash = key.toLongOrNull() ?: throw InvalidViewerConfigException("Invalid key in messages viewer config") config[hash] = parseMessage(jsonReader) } @@ -89,8 +89,8 @@ open class ViewerConfigParser { data class ConfigEntry(val messageString: String, val level: String, val tag: String) - open fun parseConfig(jsonReader: JsonReader): Map<Int, ConfigEntry> { - var messages: Map<Int, MessageEntry>? = null + open fun parseConfig(jsonReader: JsonReader): Map<Long, ConfigEntry> { + var messages: Map<Long, MessageEntry>? = null var groups: Map<String, GroupEntry>? = null var version: String? = null diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt new file mode 100644 index 000000000000..cf0876a1f072 --- /dev/null +++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 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.protolog.tool + +import perfetto.protos.PerfettoTrace.ProtoLogLevel +import perfetto.protos.PerfettoTrace.ProtoLogViewerConfig + +/** + * A builder class to construct the viewer configuration (i.e. mappings of protolog hashes to log + * message information used to decode the protolog messages) encoded as a proto message. + */ +class ViewerConfigProtoBuilder : ProtoLogTool.ProtologViewerConfigBuilder { + /** + * @return a byte array of a ProtoLogViewerConfig proto message encoding all the viewer + * configurations mapping protolog hashes to message information and log group information. + */ + override fun build(statements: Map<ProtoLogTool.LogCall, Long>): ByteArray { + val configBuilder = ProtoLogViewerConfig.newBuilder() + + val groups = statements.map { it.key.logGroup }.toSet() + val groupIds = mutableMapOf<LogGroup, Int>() + groups.forEach { + groupIds.putIfAbsent(it, groupIds.size + 1) + } + + groupIds.forEach { (group, id) -> + configBuilder.addGroups(ProtoLogViewerConfig.Group.newBuilder() + .setId(id) + .setName(group.name) + .setTag(group.tag) + .build()) + } + + statements.forEach { (log, key) -> + val groupId = groupIds[log.logGroup] ?: error("missing group id") + + configBuilder.addMessages( + ProtoLogViewerConfig.MessageData.newBuilder() + .setMessageId(key) + .setMessage(log.messageString) + .setLevel( + ProtoLogLevel.forNumber(log.logLevel.ordinal + 1)) + .setGroupId(groupId) + ) + } + + return configBuilder.build().toByteArray() + } +} diff --git a/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt b/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt index b08d859bad32..0cd02a5c5ce8 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt @@ -28,31 +28,31 @@ import org.junit.Test class CodeUtilsTest { @Test fun hash() { - assertEquals(-1259556708, CodeUtils.hash("Test.java:50", "test", + assertEquals(3883826472308915399, CodeUtils.hash("Test.java:50", "test", LogLevel.DEBUG, LogGroup("test", true, true, "TAG"))) } @Test fun hash_changeLocation() { - assertEquals(15793504, CodeUtils.hash("Test.java:10", "test2", + assertEquals(4125273133972468649, CodeUtils.hash("Test.java:10", "test2", LogLevel.DEBUG, LogGroup("test", true, true, "TAG"))) } @Test fun hash_changeLevel() { - assertEquals(-731772463, CodeUtils.hash("Test.java:50", "test", + assertEquals(2618535069521361990, CodeUtils.hash("Test.java:50", "test", LogLevel.ERROR, LogGroup("test", true, true, "TAG"))) } @Test fun hash_changeMessage() { - assertEquals(-2026343204, CodeUtils.hash("Test.java:50", "test2", + assertEquals(8907822592109789043, CodeUtils.hash("Test.java:50", "test2", LogLevel.DEBUG, LogGroup("test", true, true, "TAG"))) } @Test fun hash_changeGroup() { - assertEquals(1607870166, CodeUtils.hash("Test.java:50", "test2", + assertEquals(-1299517016176640015, CodeUtils.hash("Test.java:50", "test2", LogLevel.DEBUG, LogGroup("test2", true, true, "TAG"))) } diff --git a/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt b/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt index 3cfbb435a764..5ef2833080a2 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt @@ -16,7 +16,9 @@ package com.android.protolog.tool +import com.google.common.truth.Truth.assertThat import org.junit.Assert.assertEquals +import org.junit.Assert.assertThrows import org.junit.Test class CommandOptionsTest { @@ -35,6 +37,10 @@ class CommandOptionsTest { private const val TEST_PROTOLOGGROUP_JAR = "out/soong/.intermediates/frameworks/base/" + "services/core/services.core.wm.protologgroups/android_common/javac/" + "services.core.wm.protologgroups.jar" + private const val TEST_VIEWER_CONFIG_FILE_PATH = "/some/viewer/config/file/path.pb" + private const val TEST_LEGACY_VIEWER_CONFIG_FILE_PATH = + "/some/viewer/config/file/path.json.gz" + private const val TEST_LEGACY_OUTPUT_FILE_PATH = "/some/output/file/path.winscope" private const val TEST_SRC_JAR = "out/soong/.temp/sbox175955373/" + "services.core.wm.protolog.srcjar" private const val TEST_VIEWER_JSON = "out/soong/.temp/sbox175955373/" + @@ -42,186 +48,263 @@ class CommandOptionsTest { private const val TEST_LOG = "./test_log.pb" } - @Test(expected = InvalidCommandException::class) + @Test fun noCommand() { - CommandOptions(arrayOf()) + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(arrayOf()) + } + assertThat(exception).hasMessageThat().contains("No command specified") } - @Test(expected = InvalidCommandException::class) + @Test fun invalidCommand() { val testLine = "invalid" - CommandOptions(testLine.split(' ').toTypedArray()) + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("Unknown command") } @Test fun transformClasses() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + + val testLine = "transform-protolog-calls " + + "--protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" val cmd = CommandOptions(testLine.split(' ').toTypedArray()) assertEquals(CommandOptions.TRANSFORM_CALLS_CMD, cmd.command) assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg) - assertEquals(TEST_PROTOLOGIMPL_CLASS, cmd.protoLogImplClassNameArg) assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg) assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg) + assertEquals(TEST_VIEWER_CONFIG_FILE_PATH, cmd.viewerConfigFilePathArg) + assertEquals(TEST_LEGACY_VIEWER_CONFIG_FILE_PATH, cmd.legacyViewerConfigFilePathArg) + assertEquals(TEST_LEGACY_OUTPUT_FILE_PATH, cmd.legacyOutputFilePath) assertEquals(TEST_SRC_JAR, cmd.outputSourceJarArg) assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs) } - @Test(expected = InvalidCommandException::class) - fun transformClasses_noProtoLogClass() { + @Test + fun transformClasses_noViewerConfigFile() { val testLine = "transform-protolog-calls " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + + "--protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("--viewer-config-file-path") } - @Test(expected = InvalidCommandException::class) - fun transformClasses_noProtoLogImplClass() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + + @Test + fun transformClasses_noLegacyViewerConfigFile() { + val testLine = "transform-protolog-calls " + + "--protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) + val cmd = CommandOptions(testLine.split(' ').toTypedArray()) + assertEquals(CommandOptions.TRANSFORM_CALLS_CMD, cmd.command) + assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg) + assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg) + assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg) + assertEquals(TEST_VIEWER_CONFIG_FILE_PATH, cmd.viewerConfigFilePathArg) + assertEquals(null, cmd.legacyViewerConfigFilePathArg) + assertEquals(TEST_LEGACY_OUTPUT_FILE_PATH, cmd.legacyOutputFilePath) + assertEquals(TEST_SRC_JAR, cmd.outputSourceJarArg) + assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs) } - @Test(expected = InvalidCommandException::class) - fun transformClasses_noProtoLogCacheClass() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + + @Test + fun transformClasses_noLegacyOutputFile() { + val testLine = "transform-protolog-calls " + + "--protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) + val cmd = CommandOptions(testLine.split(' ').toTypedArray()) + assertEquals(CommandOptions.TRANSFORM_CALLS_CMD, cmd.command) + assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg) + assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg) + assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg) + assertEquals(TEST_VIEWER_CONFIG_FILE_PATH, cmd.viewerConfigFilePathArg) + assertEquals(TEST_LEGACY_VIEWER_CONFIG_FILE_PATH, cmd.legacyViewerConfigFilePathArg) + assertEquals(null, cmd.legacyOutputFilePath) + assertEquals(TEST_SRC_JAR, cmd.outputSourceJarArg) + assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs) } - @Test(expected = InvalidCommandException::class) + @Test + fun transformClasses_noProtoLogClass() { + val testLine = "transform-protolog-calls " + + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + + "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("--protolog-class") + } + + @Test fun transformClasses_noProtoLogGroupClass() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + + val testLine = "transform-protolog-calls " + + "--protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("--loggroups-class") } - @Test(expected = InvalidCommandException::class) + @Test fun transformClasses_noProtoLogGroupJar() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + + val testLine = "transform-protolog-calls " + + "--protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("--loggroups-jar") } - @Test(expected = InvalidCommandException::class) + @Test fun transformClasses_noOutJar() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + + val testLine = "transform-protolog-calls " + + "--protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + - TEST_JAVA_SRC.joinToString(" ") - CommandOptions(testLine.split(' ').toTypedArray()) + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + + "${TEST_JAVA_SRC.joinToString(" ")}" + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("--output-srcjar") } - @Test(expected = InvalidCommandException::class) + @Test fun transformClasses_noJavaInput() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + + val testLine = "transform-protolog-calls " + + "--protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + "--output-srcjar $TEST_SRC_JAR" - CommandOptions(testLine.split(' ').toTypedArray()) + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("No java source input files") } - @Test(expected = InvalidCommandException::class) + @Test fun transformClasses_invalidProtoLogClass() { - val testLine = "transform-protolog-calls --protolog-class invalid " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + - "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + - "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + - "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) - } - - @Test(expected = InvalidCommandException::class) - fun transformClasses_invalidProtoLogImplClass() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class invalid " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + - "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + - "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + - "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) - } - - @Test(expected = InvalidCommandException::class) - fun transformClasses_invalidProtoLogCacheClass() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + - "--protolog-cache-class invalid " + + val testLine = "transform-protolog-calls " + + "--protolog-class invalid " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("class name invalid") } - @Test(expected = InvalidCommandException::class) + @Test fun transformClasses_invalidProtoLogGroupClass() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + + val testLine = "transform-protolog-calls " + + "--protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class invalid " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("class name invalid") } - @Test(expected = InvalidCommandException::class) + @Test fun transformClasses_invalidProtoLogGroupJar() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + + val testLine = "transform-protolog-calls " + + "--protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar invalid.txt " + + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat() + .contains("Jar file required, got invalid.txt instead") } - @Test(expected = InvalidCommandException::class) + @Test fun transformClasses_invalidOutJar() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + + val testLine = "transform-protolog-calls " + + "--protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + - "--output-srcjar invalid.db ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + + "--output-srcjar invalid.pb ${TEST_JAVA_SRC.joinToString(" ")}" + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat() + .contains("Source jar file required, got invalid.pb instead") } - @Test(expected = InvalidCommandException::class) + @Test fun transformClasses_invalidJavaInput() { - val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + - "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + - "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + - "--output-srcjar $TEST_SRC_JAR invalid.py" - CommandOptions(testLine.split(' ').toTypedArray()) + val testLine = "transform-protolog-calls " + + "--protolog-class $TEST_PROTOLOG_CLASS " + + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + + "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " + + "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " + + "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " + + "--output-srcjar $TEST_SRC_JAR invalid.py" + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat() + .contains("Not a java or kotlin source file invalid.py") } - @Test(expected = InvalidCommandException::class) + @Test fun transformClasses_unknownParam() { val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + "--unknown test --protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " + @@ -229,59 +312,88 @@ class CommandOptionsTest { "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("--unknown") } - @Test(expected = InvalidCommandException::class) + @Test fun transformClasses_noValue() { val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " + - "--protolog-impl-class " + - "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " + - "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + + "--loggroups-class " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("No value for --loggroups-class") } @Test - fun generateConfig() { - val testLine = "generate-viewer-config --protolog-class $TEST_PROTOLOG_CLASS " + + fun generateConfig_json() { + val testLine = "generate-viewer-config " + + "--protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + - "--viewer-conf $TEST_VIEWER_JSON ${TEST_JAVA_SRC.joinToString(" ")}" + "--viewer-config-type json " + + "--viewer-config $TEST_VIEWER_JSON ${TEST_JAVA_SRC.joinToString(" ")}" val cmd = CommandOptions(testLine.split(' ').toTypedArray()) assertEquals(CommandOptions.GENERATE_CONFIG_CMD, cmd.command) assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg) assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg) assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg) - assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigJsonArg) + assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigFileNameArg) assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs) } - @Test(expected = InvalidCommandException::class) + @Test + fun generateConfig_proto() { + val testLine = "generate-viewer-config " + + "--protolog-class $TEST_PROTOLOG_CLASS " + + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + + "--viewer-config-type proto " + + "--viewer-config $TEST_VIEWER_JSON ${TEST_JAVA_SRC.joinToString(" ")}" + val cmd = CommandOptions(testLine.split(' ').toTypedArray()) + assertEquals(CommandOptions.GENERATE_CONFIG_CMD, cmd.command) + assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg) + assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg) + assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg) + assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigFileNameArg) + assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs) + } + + @Test fun generateConfig_noViewerConfig() { val testLine = "generate-viewer-config --protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + TEST_JAVA_SRC.joinToString(" ") - CommandOptions(testLine.split(' ').toTypedArray()) + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("--viewer-config required") } - @Test(expected = InvalidCommandException::class) + @Test fun generateConfig_invalidViewerConfig() { val testLine = "generate-viewer-config --protolog-class $TEST_PROTOLOG_CLASS " + "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " + "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " + - "--viewer-conf invalid.yaml ${TEST_JAVA_SRC.joinToString(" ")}" - CommandOptions(testLine.split(' ').toTypedArray()) + "--viewer-config invalid.yaml ${TEST_JAVA_SRC.joinToString(" ")}" + val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) { + CommandOptions(testLine.split(' ').toTypedArray()) + } + assertThat(exception).hasMessageThat().contains("required, got invalid.yaml instead") } @Test fun readLog() { - val testLine = "read-log --viewer-conf $TEST_VIEWER_JSON $TEST_LOG" + val testLine = "read-log --viewer-config $TEST_VIEWER_JSON $TEST_LOG" val cmd = CommandOptions(testLine.split(' ').toTypedArray()) assertEquals(CommandOptions.READ_LOG_CMD, cmd.command) - assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigJsonArg) + assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigFileNameArg) assertEquals(TEST_LOG, cmd.logProtofileArg) } } diff --git a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt index 0d2b91d6cfb8..822118cc5343 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt @@ -16,22 +16,24 @@ package com.android.protolog.tool -import org.junit.Assert -import org.junit.Assert.assertTrue -import org.junit.Test +import com.android.protolog.tool.ProtoLogTool.PROTOLOG_IMPL_SRC_PATH +import com.google.common.truth.Truth import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.File import java.io.FileNotFoundException import java.io.OutputStream import java.util.jar.JarInputStream +import java.util.regex.Pattern +import org.junit.Assert +import org.junit.Test class EndToEndTest { @Test fun e2e_transform() { val output = run( - src = "frameworks/base/org/example/Example.java" to """ + srcs = mapOf("frameworks/base/org/example/Example.java" to """ package org.example; import com.android.internal.protolog.common.ProtoLog; import static com.android.internal.protolog.ProtoLogGroup.GROUP; @@ -43,26 +45,29 @@ class EndToEndTest { ProtoLog.d(GROUP, "Example: %s %d", argString, argInt); } } - """.trimIndent(), + """.trimIndent()), logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("transform-protolog-calls", "--protolog-class", "com.android.internal.protolog.common.ProtoLog", - "--protolog-impl-class", "com.android.internal.protolog.ProtoLogImpl", - "--protolog-cache-class", - "com.android.server.wm.ProtoLogCache", "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup", "--loggroups-jar", "not_required.jar", + "--viewer-config-file-path", "not_required.pb", "--output-srcjar", "out.srcjar", "frameworks/base/org/example/Example.java")) ) val outSrcJar = assertLoadSrcJar(output, "out.srcjar") - assertTrue(" 2066303299," in outSrcJar["frameworks/base/org/example/Example.java"]!!) + Truth.assertThat(outSrcJar["frameworks/base/org/example/Example.java"]) + .containsMatch(Pattern.compile("\\{ String protoLogParam0 = " + + "String\\.valueOf\\(argString\\); long protoLogParam1 = argInt; " + + "com\\.android\\.internal\\.protolog.ProtoLogImpl_.*\\.d\\(" + + "GROUP, -6872339441335321086L, 4, null, protoLogParam0, protoLogParam1" + + "\\); \\}")) } @Test fun e2e_viewerConfig() { val output = run( - src = "frameworks/base/org/example/Example.java" to """ + srcs = mapOf("frameworks/base/org/example/Example.java" to """ package org.example; import com.android.internal.protolog.common.ProtoLog; import static com.android.internal.protolog.ProtoLogGroup.GROUP; @@ -74,17 +79,27 @@ class EndToEndTest { ProtoLog.d(GROUP, "Example: %s %d", argString, argInt); } } - """.trimIndent(), + """.trimIndent()), logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("generate-viewer-config", "--protolog-class", "com.android.internal.protolog.common.ProtoLog", "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup", "--loggroups-jar", "not_required.jar", - "--viewer-conf", "out.json", + "--viewer-config-type", "json", + "--viewer-config", "out.json", "frameworks/base/org/example/Example.java")) ) val viewerConfigJson = assertLoadText(output, "out.json") - assertTrue("\"2066303299\"" in viewerConfigJson) + Truth.assertThat(viewerConfigJson).contains(""" + "messages": { + "-6872339441335321086": { + "message": "Example: %s %d", + "level": "DEBUG", + "group": "GROUP", + "at": "org\/example\/Example.java" + } + } + """.trimIndent()) } private fun assertLoadSrcJar( @@ -112,21 +127,46 @@ class EndToEndTest { } fun run( - src: Pair<String, String>, + srcs: Map<String, String>, logGroup: LogGroup, commandOptions: CommandOptions ): Map<String, ByteArray> { val outputs = mutableMapOf<String, ByteArrayOutputStream>() + val srcs = srcs.toMutableMap() + srcs[PROTOLOG_IMPL_SRC_PATH] = """ + package com.android.internal.protolog; + + import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_OUTPUT_FILE_PATH; + import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_VIEWER_CONFIG_PATH; + import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH; + + import com.android.internal.protolog.common.ProtoLogToolInjected; + + public class ProtoLogImpl { + @ProtoLogToolInjected(VIEWER_CONFIG_PATH) + private static String sViewerConfigPath; + + @ProtoLogToolInjected(LEGACY_VIEWER_CONFIG_PATH) + private static String sLegacyViewerConfigPath; + + @ProtoLogToolInjected(LEGACY_OUTPUT_FILE_PATH) + private static String sLegacyOutputFilePath; + } + """.trimIndent() + ProtoLogTool.injector = object : ProtoLogTool.Injector { override fun fileOutputStream(file: String): OutputStream = ByteArrayOutputStream().also { outputs[file] = it } override fun readText(file: File): String { - if (file.path == src.first) { - return src.second + for (src in srcs.entries) { + val filePath = src.key + if (file.path == filePath) { + return src.value + } } - throw FileNotFoundException("expected: ${src.first}, but was $file") + throw FileNotFoundException("$file not found in [${srcs.keys.joinToString()}].") } override fun readLogGroups(jarPath: String, className: String) = mapOf( diff --git a/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt index 512d90c725fe..1d3270268843 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt @@ -35,7 +35,7 @@ import java.util.Locale class LogParserTest { private val configParser: ViewerConfigParser = mock(ViewerConfigParser::class.java) private val parser = LogParser(configParser) - private var config: MutableMap<Int, ViewerConfigParser.ConfigEntry> = mutableMapOf() + private var config: MutableMap<Long, ViewerConfigParser.ConfigEntry> = mutableMapOf() private var outStream: OutputStream = ByteArrayOutputStream() private var printStream: PrintStream = PrintStream(outStream) private val dateFormat = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US) diff --git a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt index 90b8059dae1c..5e50f71d75cc 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt @@ -22,7 +22,7 @@ import com.github.javaparser.ast.expr.MethodCallExpr import org.junit.Assert.assertEquals import org.junit.Test -class ProtoLogCallProcessorTest { +class ProtoLogCallProcessorImplTest { private data class LogCall( val call: MethodCallExpr, val messageString: String, @@ -32,8 +32,11 @@ class ProtoLogCallProcessorTest { private val groupMap: MutableMap<String, LogGroup> = mutableMapOf() private val calls: MutableList<LogCall> = mutableListOf() - private val visitor = ProtoLogCallProcessor("org.example.ProtoLog", "org.example.ProtoLogGroup", - groupMap) + private val visitor = ProtoLogCallProcessorImpl( + "org.example.ProtoLog", + "org.example.ProtoLogGroup", + groupMap + ) private val processor = object : ProtoLogCallVisitor { override fun processCall( call: MethodCallExpr, diff --git a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogToolTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogToolTest.kt deleted file mode 100644 index ea9a58d859af..000000000000 --- a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogToolTest.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2019 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.protolog.tool - -import org.junit.Assert.assertEquals -import org.junit.Test - -class ProtoLogToolTest { - - @Test - fun generateLogGroupCache() { - val groups = mapOf( - "GROUP1" to LogGroup("GROUP1", true, true, "TAG1"), - "GROUP2" to LogGroup("GROUP2", true, true, "TAG2") - ) - val code = ProtoLogTool.generateLogGroupCache("org.example", "ProtoLog\$Cache", - groups, "org.example.ProtoLogImpl", "org.example.ProtoLogGroups") - - assertEquals(""" - package org.example; - - public class ProtoLog${'$'}Cache { - public static boolean GROUP1_enabled = false; - public static boolean GROUP2_enabled = false; - - static { - org.example.ProtoLogImpl.sCacheUpdater = ProtoLog${'$'}Cache::update; - update(); - } - - static void update() { - GROUP1_enabled = org.example.ProtoLogImpl.isEnabled(org.example.ProtoLogGroups.GROUP1); - GROUP2_enabled = org.example.ProtoLogImpl.isEnabled(org.example.ProtoLogGroups.GROUP2); - } - } - """.trimIndent(), code) - } -}
\ No newline at end of file diff --git a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt index f52bfeccea51..de0b5bae118e 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt @@ -20,17 +20,14 @@ import com.android.internal.protolog.common.LogLevel import com.github.javaparser.StaticJavaParser import com.github.javaparser.ast.CompilationUnit import com.github.javaparser.ast.expr.MethodCallExpr -import com.github.javaparser.ast.stmt.IfStmt +import com.google.common.truth.Truth import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse import org.junit.Test import org.mockito.Mockito class SourceTransformerTest { companion object { - private const val PROTO_LOG_IMPL_PATH = "org.example.ProtoLogImpl" - /* ktlint-disable max-line-length */ private val TEST_CODE = """ package org.example; @@ -79,7 +76,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } + { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -89,20 +86,20 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 1780316587, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); + { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); } } } """.trimIndent() - private val TRANSFORMED_CODE_MULTICALL_TEXT_ENABLED = """ + private val TRANSFORMED_CODE_MULTICALL_TEXT = """ package org.example; class Test { void test() { - if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } - if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } + { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } + { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -112,7 +109,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogCache.TEST_GROUP_enabled) { org.example.ProtoLogImpl.w(TEST_GROUP, -1741986185, 0, "test", (Object[]) null); } + { org.example.ProtoLogImpl.w(TEST_GROUP, 3218600869538902408L, 0, "test", (Object[]) null); } } } """.trimIndent() @@ -122,7 +119,7 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, null, protoLogParam0, protoLogParam1); } + { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, null, protoLogParam0, protoLogParam1); } } } """.trimIndent() @@ -132,43 +129,19 @@ class SourceTransformerTest { class Test { void test() { - if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 1780316587, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); + { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); } } } """.trimIndent() - private val TRANSFORMED_CODE_DISABLED = """ - package org.example; - - class Test { - void test() { - if (false) { /* TEST_GROUP is disabled */ ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); } - } - } - """.trimIndent() - - private val TRANSFORMED_CODE_MULTILINE_DISABLED = """ - package org.example; - - class Test { - void test() { - if (false) { /* TEST_GROUP is disabled */ ProtoLog.w(TEST_GROUP, "test %d %f " + "abc %s\n test", 100, 0.1, "test"); - - } - } - } - """.trimIndent() - /* ktlint-enable max-line-length */ - private const val PATH = "com.example.Test.java" } private val processor: ProtoLogCallProcessor = Mockito.mock(ProtoLogCallProcessor::class.java) private val implName = "org.example.ProtoLogImpl" - private val cacheName = "org.example.ProtoLogCache" - private val sourceJarWriter = SourceTransformer(implName, cacheName, processor) + private val sourceJarWriter = SourceTransformer(implName, processor) private fun <T> any(type: Class<T>): T = Mockito.any<T>(type) @@ -176,9 +149,12 @@ class SourceTransformerTest { fun processClass_textEnabled() { var code = StaticJavaParser.parse(TEST_CODE) - Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java), any(String::class.java))) - .thenAnswer { invocation -> + Mockito.`when`(processor.process( + any(CompilationUnit::class.java), + any(ProtoLogCallVisitor::class.java), + any(MethodCallVisitor::class.java), + any(String::class.java)) + ).thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f", @@ -190,18 +166,15 @@ class SourceTransformerTest { val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code) code = StaticJavaParser.parse(out) - val ifStmts = code.findAll(IfStmt::class.java) - assertEquals(1, ifStmts.size) - val ifStmt = ifStmts[0] - assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString()) - assertFalse(ifStmt.elseStmt.isPresent) - assertEquals(3, ifStmt.thenStmt.childNodes.size) - val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr - assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString()) + val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter { + it.scope.orElse(null)?.toString() == implName + } + Truth.assertThat(protoLogCalls).hasSize(1) + val methodCall = protoLogCalls[0] as MethodCallExpr assertEquals("w", methodCall.name.asString()) assertEquals(6, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("1698911065", methodCall.arguments[1].toString()) + assertEquals("-1473209266730422156L", methodCall.arguments[1].toString()) assertEquals(0b1001.toString(), methodCall.arguments[2].toString()) assertEquals("\"test %d %f\"", methodCall.arguments[3].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) @@ -213,9 +186,12 @@ class SourceTransformerTest { fun processClass_textEnabledMulticalls() { var code = StaticJavaParser.parse(TEST_CODE_MULTICALLS) - Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java), any(String::class.java))) - .thenAnswer { invocation -> + Mockito.`when`(processor.process( + any(CompilationUnit::class.java), + any(ProtoLogCallVisitor::class.java), + any(MethodCallVisitor::class.java), + any(String::class.java)) + ).thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor val calls = code.findAll(MethodCallExpr::class.java) @@ -232,32 +208,32 @@ class SourceTransformerTest { val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, PATH, code) code = StaticJavaParser.parse(out) - val ifStmts = code.findAll(IfStmt::class.java) - assertEquals(3, ifStmts.size) - val ifStmt = ifStmts[1] - assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString()) - assertFalse(ifStmt.elseStmt.isPresent) - assertEquals(3, ifStmt.thenStmt.childNodes.size) - val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr - assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString()) + val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter { + it.scope.orElse(null)?.toString() == implName + } + Truth.assertThat(protoLogCalls).hasSize(3) + val methodCall = protoLogCalls[0] as MethodCallExpr assertEquals("w", methodCall.name.asString()) assertEquals(6, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("1698911065", methodCall.arguments[1].toString()) + assertEquals("-1473209266730422156L", methodCall.arguments[1].toString()) assertEquals(0b1001.toString(), methodCall.arguments[2].toString()) assertEquals("\"test %d %f\"", methodCall.arguments[3].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) assertEquals("protoLogParam1", methodCall.arguments[5].toString()) - assertEquals(TRANSFORMED_CODE_MULTICALL_TEXT_ENABLED, out) + assertEquals(TRANSFORMED_CODE_MULTICALL_TEXT, out) } @Test fun processClass_textEnabledMultiline() { var code = StaticJavaParser.parse(TEST_CODE_MULTILINE) - Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java), any(String::class.java))) - .thenAnswer { invocation -> + Mockito.`when`(processor.process( + any(CompilationUnit::class.java), + any(ProtoLogCallVisitor::class.java), + any(MethodCallVisitor::class.java), + any(String::class.java)) + ).thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], @@ -270,18 +246,15 @@ class SourceTransformerTest { val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code) code = StaticJavaParser.parse(out) - val ifStmts = code.findAll(IfStmt::class.java) - assertEquals(1, ifStmts.size) - val ifStmt = ifStmts[0] - assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString()) - assertFalse(ifStmt.elseStmt.isPresent) - assertEquals(4, ifStmt.thenStmt.childNodes.size) - val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[1] as MethodCallExpr - assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString()) + val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter { + it.scope.orElse(null)?.toString() == implName + } + Truth.assertThat(protoLogCalls).hasSize(1) + val methodCall = protoLogCalls[0] as MethodCallExpr assertEquals("w", methodCall.name.asString()) assertEquals(7, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("1780316587", methodCall.arguments[1].toString()) + assertEquals("-4447034859795564700L", methodCall.arguments[1].toString()) assertEquals(0b001001.toString(), methodCall.arguments[2].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) assertEquals("protoLogParam1", methodCall.arguments[5].toString()) @@ -293,9 +266,12 @@ class SourceTransformerTest { fun processClass_noParams() { var code = StaticJavaParser.parse(TEST_CODE_NO_PARAMS) - Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java), any(String::class.java))) - .thenAnswer { invocation -> + Mockito.`when`(processor.process( + any(CompilationUnit::class.java), + any(ProtoLogCallVisitor::class.java), + any(MethodCallVisitor::class.java), + any(String::class.java)) + ).thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test", @@ -307,18 +283,15 @@ class SourceTransformerTest { val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, PATH, code) code = StaticJavaParser.parse(out) - val ifStmts = code.findAll(IfStmt::class.java) - assertEquals(1, ifStmts.size) - val ifStmt = ifStmts[0] - assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString()) - assertFalse(ifStmt.elseStmt.isPresent) - assertEquals(1, ifStmt.thenStmt.childNodes.size) - val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr - assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString()) + val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter { + it.scope.orElse(null)?.toString() == implName + } + Truth.assertThat(protoLogCalls).hasSize(1) + val methodCall = protoLogCalls[0] as MethodCallExpr assertEquals("w", methodCall.name.asString()) assertEquals(5, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("-1741986185", methodCall.arguments[1].toString()) + assertEquals("3218600869538902408L", methodCall.arguments[1].toString()) assertEquals(0.toString(), methodCall.arguments[2].toString()) assertEquals(TRANSFORMED_CODE_NO_PARAMS, out) } @@ -327,9 +300,12 @@ class SourceTransformerTest { fun processClass_textDisabled() { var code = StaticJavaParser.parse(TEST_CODE) - Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java), any(String::class.java))) - .thenAnswer { invocation -> + Mockito.`when`(processor.process( + any(CompilationUnit::class.java), + any(ProtoLogCallVisitor::class.java), + any(MethodCallVisitor::class.java), + any(String::class.java)) + ).thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f", @@ -341,18 +317,15 @@ class SourceTransformerTest { val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code) code = StaticJavaParser.parse(out) - val ifStmts = code.findAll(IfStmt::class.java) - assertEquals(1, ifStmts.size) - val ifStmt = ifStmts[0] - assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString()) - assertFalse(ifStmt.elseStmt.isPresent) - assertEquals(3, ifStmt.thenStmt.childNodes.size) - val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr - assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString()) + val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter { + it.scope.orElse(null)?.toString() == implName + } + Truth.assertThat(protoLogCalls).hasSize(1) + val methodCall = protoLogCalls[0] as MethodCallExpr assertEquals("w", methodCall.name.asString()) assertEquals(6, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("1698911065", methodCall.arguments[1].toString()) + assertEquals("-1473209266730422156L", methodCall.arguments[1].toString()) assertEquals(0b1001.toString(), methodCall.arguments[2].toString()) assertEquals("null", methodCall.arguments[3].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) @@ -364,9 +337,12 @@ class SourceTransformerTest { fun processClass_textDisabledMultiline() { var code = StaticJavaParser.parse(TEST_CODE_MULTILINE) - Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java), any(String::class.java))) - .thenAnswer { invocation -> + Mockito.`when`(processor.process( + any(CompilationUnit::class.java), + any(ProtoLogCallVisitor::class.java), + any(MethodCallVisitor::class.java), + any(String::class.java)) + ).thenAnswer { invocation -> val visitor = invocation.arguments[1] as ProtoLogCallVisitor visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], @@ -379,18 +355,15 @@ class SourceTransformerTest { val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code) code = StaticJavaParser.parse(out) - val ifStmts = code.findAll(IfStmt::class.java) - assertEquals(1, ifStmts.size) - val ifStmt = ifStmts[0] - assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString()) - assertFalse(ifStmt.elseStmt.isPresent) - assertEquals(4, ifStmt.thenStmt.childNodes.size) - val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[1] as MethodCallExpr - assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString()) + val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter { + it.scope.orElse(null)?.toString() == implName + } + Truth.assertThat(protoLogCalls).hasSize(1) + val methodCall = protoLogCalls[0] as MethodCallExpr assertEquals("w", methodCall.name.asString()) assertEquals(7, methodCall.arguments.size) assertEquals("TEST_GROUP", methodCall.arguments[0].toString()) - assertEquals("1780316587", methodCall.arguments[1].toString()) + assertEquals("-4447034859795564700L", methodCall.arguments[1].toString()) assertEquals(0b001001.toString(), methodCall.arguments[2].toString()) assertEquals("null", methodCall.arguments[3].toString()) assertEquals("protoLogParam0", methodCall.arguments[4].toString()) @@ -398,55 +371,4 @@ class SourceTransformerTest { assertEquals("protoLogParam2", methodCall.arguments[6].toString()) assertEquals(TRANSFORMED_CODE_MULTILINE_TEXT_DISABLED, out) } - - @Test - fun processClass_disabled() { - var code = StaticJavaParser.parse(TEST_CODE) - - Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java), any(String::class.java))) - .thenAnswer { invocation -> - val visitor = invocation.arguments[1] as ProtoLogCallVisitor - - visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f", - LogLevel.WARN, LogGroup("TEST_GROUP", false, true, "WM_TEST")) - - invocation.arguments[0] as CompilationUnit - } - - val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code) - code = StaticJavaParser.parse(out) - - val ifStmts = code.findAll(IfStmt::class.java) - assertEquals(1, ifStmts.size) - val ifStmt = ifStmts[0] - assertEquals("false", ifStmt.condition.toString()) - assertEquals(TRANSFORMED_CODE_DISABLED, out) - } - - @Test - fun processClass_disabledMultiline() { - var code = StaticJavaParser.parse(TEST_CODE_MULTILINE) - - Mockito.`when`(processor.process(any(CompilationUnit::class.java), - any(ProtoLogCallVisitor::class.java), any(String::class.java))) - .thenAnswer { invocation -> - val visitor = invocation.arguments[1] as ProtoLogCallVisitor - - visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], - "test %d %f abc %s\n test", LogLevel.WARN, LogGroup("TEST_GROUP", - false, true, "WM_TEST")) - - invocation.arguments[0] as CompilationUnit - } - - val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code) - code = StaticJavaParser.parse(out) - - val ifStmts = code.findAll(IfStmt::class.java) - assertEquals(1, ifStmts.size) - val ifStmt = ifStmts[0] - assertEquals("false", ifStmt.condition.toString()) - assertEquals(TRANSFORMED_CODE_MULTILINE_DISABLED, out) - } } diff --git a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt index 52dce21944f6..d27ae88fc488 100644 --- a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt +++ b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt @@ -18,13 +18,12 @@ package com.android.protolog.tool import com.android.internal.protolog.common.LogLevel import com.android.json.stream.JsonReader -import com.android.protolog.tool.ViewerConfigBuilder.LogCall +import com.android.protolog.tool.ProtoLogTool.LogCall +import java.io.StringReader import org.junit.Assert.assertEquals import org.junit.Test -import org.mockito.Mockito -import java.io.StringReader -class ViewerConfigBuilderTest { +class ViewerConfigJsonBuilderTest { companion object { private val TAG1 = "WM_TEST" private val TAG2 = "WM_DEBUG" @@ -39,20 +38,22 @@ class ViewerConfigBuilderTest { private const val PATH = "/tmp/test.java" } - private val configBuilder = ViewerConfigBuilder(Mockito.mock(ProtoLogCallProcessor::class.java)) + private val configBuilder = ViewerConfigJsonBuilder() - private fun parseConfig(json: String): Map<Int, ViewerConfigParser.ConfigEntry> { + private fun parseConfig(json: String): Map<Long, ViewerConfigParser.ConfigEntry> { return ViewerConfigParser().parseConfig(JsonReader(StringReader(json))) } @Test fun processClass() { - configBuilder.addLogCalls(listOf( + val logCallRegistry = ProtoLogTool.LogCallRegistry() + logCallRegistry.addLogCalls(listOf( LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH), LogCall(TEST2.messageString, LogLevel.DEBUG, GROUP2, PATH), - LogCall(TEST3.messageString, LogLevel.ERROR, GROUP3, PATH)).withContext()) + LogCall(TEST3.messageString, LogLevel.ERROR, GROUP3, PATH))) - val parsedConfig = parseConfig(configBuilder.build()) + val parsedConfig = parseConfig( + configBuilder.build(logCallRegistry.getStatements()).toString(Charsets.UTF_8)) assertEquals(3, parsedConfig.size) assertEquals(TEST1, parsedConfig[CodeUtils.hash(PATH, TEST1.messageString, LogLevel.INFO, GROUP1)]) @@ -64,32 +65,16 @@ class ViewerConfigBuilderTest { @Test fun processClass_nonUnique() { - configBuilder.addLogCalls(listOf( + val logCallRegistry = ProtoLogTool.LogCallRegistry() + logCallRegistry.addLogCalls(listOf( LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH), LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH), - LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH)).withContext()) + LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH))) - val parsedConfig = parseConfig(configBuilder.build()) + val parsedConfig = parseConfig( + configBuilder.build(logCallRegistry.getStatements()).toString(Charsets.UTF_8)) assertEquals(1, parsedConfig.size) assertEquals(TEST1, parsedConfig[CodeUtils.hash(PATH, TEST1.messageString, - LogLevel.INFO, GROUP1)]) - } - - @Test - fun processClass_disabled() { - configBuilder.addLogCalls(listOf( - LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH), - LogCall(TEST2.messageString, LogLevel.DEBUG, GROUP_DISABLED, PATH), - LogCall(TEST3.messageString, LogLevel.ERROR, GROUP_TEXT_DISABLED, PATH)) - .withContext()) - - val parsedConfig = parseConfig(configBuilder.build()) - assertEquals(2, parsedConfig.size) - assertEquals(TEST1, parsedConfig[CodeUtils.hash( - PATH, TEST1.messageString, LogLevel.INFO, GROUP1)]) - assertEquals(TEST3, parsedConfig[CodeUtils.hash( - PATH, TEST3.messageString, LogLevel.ERROR, GROUP_TEXT_DISABLED)]) + LogLevel.INFO, GROUP1)]) } - - private fun List<LogCall>.withContext() = map { it to ParsingContext() } } |